dplayx: Code to send CreatePlayer messages
[wine/gsoc_dplay.git] / dlls / dplayx / dplayx_messages.c
blobc4c998d3efbedf194087dd1e28cf307d9919ab49
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_FillSuperPackedPlayer( IDirectPlay2Impl* lpDP,
54 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer,
55 LPVOID lpData,
56 BOOL bIsGroup,
57 BOOL bAnsi );
58 static DWORD DP_MSG_FillPackedPlayer( IDirectPlay2Impl* lpDP,
59 LPDPLAYI_PACKEDPLAYER lpPackedPlayer,
60 LPVOID lpData,
61 BOOL bIsGroup,
62 BOOL bAnsi );
63 DWORD DP_CopyString( LPVOID destination, LPVOID source, BOOL bAnsi );
66 /* Create the message reception thread to allow the application to receive
67 * asynchronous message reception
69 DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
70 HANDLE hDeath, HANDLE hConnRead )
72 DWORD dwMsgThreadId;
73 LPMSGTHREADINFO lpThreadInfo;
75 lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
76 if( lpThreadInfo == NULL )
78 return 0;
81 /* The notify event may or may not exist. Depends if async comm or not */
82 if( hNotifyEvent &&
83 !DuplicateHandle( GetCurrentProcess(), hNotifyEvent,
84 GetCurrentProcess(), &lpThreadInfo->hNotifyEvent,
85 0, FALSE, DUPLICATE_SAME_ACCESS ) )
87 ERR( "Unable to duplicate event handle\n" );
88 goto error;
91 /* These 3 handles don't need to be duplicated because we don't keep a
92 * reference to them where they're created. They're created specifically
93 * for the message thread
95 lpThreadInfo->hStart = hStart;
96 lpThreadInfo->hDeath = hDeath;
97 lpThreadInfo->hSettingRead = hConnRead;
99 if( !CreateThread( NULL, /* Security attribs */
100 0, /* Stack */
101 DPL_MSG_ThreadMain, /* Msg reception function */
102 lpThreadInfo, /* Msg reception func parameter */
103 0, /* Flags */
104 &dwMsgThreadId /* Updated with thread id */
108 ERR( "Unable to create msg thread\n" );
109 goto error;
112 /* FIXME: Should I be closing the handle to the thread or does that
113 terminate the thread? */
115 return dwMsgThreadId;
117 error:
119 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
121 return 0;
124 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
126 LPMSGTHREADINFO lpThreadInfo = lpContext;
127 DWORD dwWaitResult;
129 TRACE( "Msg thread created. Waiting on app startup\n" );
131 /* Wait to ensure that the lobby application is started w/ 1 min timeout */
132 dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ );
133 if( dwWaitResult == WAIT_TIMEOUT )
135 FIXME( "Should signal app/wait creation failure (0x%08x)\n", dwWaitResult );
136 goto end_of_thread;
139 /* Close this handle as it's not needed anymore */
140 CloseHandle( lpThreadInfo->hStart );
141 lpThreadInfo->hStart = 0;
143 /* Wait until the lobby knows what it is */
144 dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE );
145 if( dwWaitResult == WAIT_TIMEOUT )
147 ERR( "App Read connection setting timeout fail (0x%08x)\n", dwWaitResult );
150 /* Close this handle as it's not needed anymore */
151 CloseHandle( lpThreadInfo->hSettingRead );
152 lpThreadInfo->hSettingRead = 0;
154 TRACE( "App created && initialized starting main message reception loop\n" );
156 for ( ;; )
158 MSG lobbyMsg;
159 GetMessageW( &lobbyMsg, 0, 0, 0 );
162 end_of_thread:
163 TRACE( "Msg thread exiting!\n" );
164 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
166 return 0;
169 /* DP messaging stuff */
170 static HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
171 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
172 WORD wReplyCommandId );
173 static LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
174 LPVOID* lplpReplyHdr, LPVOID* lplpReplyMsg,
175 LPDWORD lpdwMsgBodySize );
178 static
179 HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
180 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, WORD wReplyCommandId )
182 lpReplyStructList->replyExpected.hReceipt = CreateEventW( NULL, FALSE, FALSE, NULL );
183 lpReplyStructList->replyExpected.wExpectedReply = wReplyCommandId;
184 lpReplyStructList->replyExpected.lpReplyHdr = NULL;
185 lpReplyStructList->replyExpected.lpReplyMsg = NULL;
186 lpReplyStructList->replyExpected.dwMsgBodySize = 0;
188 /* Insert into the message queue while locked */
189 EnterCriticalSection( &This->unk->DP_lock );
190 DPQ_INSERT( This->dp2->replysExpected, lpReplyStructList, replysExpected );
191 LeaveCriticalSection( &This->unk->DP_lock );
193 return lpReplyStructList->replyExpected.hReceipt;
196 static
197 LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
198 LPVOID* lplpReplyHdr, LPVOID* lplpReplyMsg,
199 LPDWORD lpdwMsgBodySize )
201 CloseHandle( lpReplyStructList->replyExpected.hReceipt );
203 if ( lplpReplyHdr )
205 *lplpReplyHdr = lpReplyStructList->replyExpected.lpReplyHdr;
208 *lplpReplyMsg = lpReplyStructList->replyExpected.lpReplyMsg;
209 *lpdwMsgBodySize = lpReplyStructList->replyExpected.dwMsgBodySize;
211 return lpReplyStructList->replyExpected.lpReplyMsg;
214 HRESULT DP_MSG_PackMessage( IDirectPlay2AImpl* This, LPVOID* lpMsg,
215 LPDWORD lpMessageSize )
217 LPVOID lpPacket;
218 LPDPSP_MSG_PACKET lpPacketBody;
220 TRACE( "Packing message with command 0x%x\n",
221 ( (LPDPSP_MSG_ENVELOPE)
222 (((LPBYTE) *lpMsg) + This->dp2->spData.dwSPHeaderSize))->wCommandId );
223 FIXME( "TODO: Segment the package if needed\n" );
225 lpPacket = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
226 *lpMessageSize + sizeof(DPSP_MSG_PACKET) );
227 lpPacketBody = (LPDPSP_MSG_PACKET)( (LPBYTE) lpPacket +
228 This->dp2->spData.dwSPHeaderSize );
230 /* TODO: When do we have to send a DPMSGCMD_PACKET2_DATA? */
231 lpPacketBody->envelope.dwMagic = DPMSG_SIGNATURE;
232 lpPacketBody->envelope.wCommandId = DPMSGCMD_PACKET;
233 lpPacketBody->envelope.wVersion = DX61AVERSION;
235 CoCreateGuid( &lpPacketBody->GuidMessage );
236 lpPacketBody->PacketIndex = 0;
237 lpPacketBody->DataSize = *lpMessageSize - This->dp2->spData.dwSPHeaderSize;
238 lpPacketBody->Offset = 0;
239 lpPacketBody->TotalPackets = 1;
240 lpPacketBody->MessageSize = *lpMessageSize - This->dp2->spData.dwSPHeaderSize;
241 lpPacketBody->PackedOffset = 0;
243 /* Copy the header of the original message */
244 CopyMemory( lpPacket, *lpMsg, This->dp2->spData.dwSPHeaderSize );
245 /* Copy the body of the original message */
246 CopyMemory( lpPacketBody + 1,
247 ((LPBYTE) *lpMsg) + This->dp2->spData.dwSPHeaderSize,
248 *lpMessageSize - This->dp2->spData.dwSPHeaderSize );
249 *lpMessageSize += sizeof(DPSP_MSG_PACKET);
251 HeapFree( GetProcessHeap(), 0, *lpMsg );
252 *lpMsg = lpPacket;
254 return DP_OK;
257 HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
258 LPDPID lpdpidAllocatedId )
260 LPVOID lpMsg;
261 LPDPSP_MSG_REQUESTPLAYERID lpMsgBody;
262 DWORD dwMsgSize;
263 HRESULT hr = DP_OK;
265 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
267 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
269 lpMsgBody = (LPDPSP_MSG_REQUESTPLAYERID)( (LPBYTE)lpMsg +
270 This->dp2->spData.dwSPHeaderSize );
272 /* Compose dplay message envelope */
273 lpMsgBody->envelope.dwMagic = DPMSG_SIGNATURE;
274 lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTPLAYERID;
275 lpMsgBody->envelope.wVersion = DX61AVERSION;
277 /* Compose the body of the message */
278 lpMsgBody->Flags = dwFlags;
280 /* Send the message */
282 DPSP_SENDDATA data;
284 data.dwFlags = DPSEND_GUARANTEED;
285 data.idPlayerTo = 0; /* Name server */
286 data.idPlayerFrom = 0; /* Sending from DP */
287 data.lpMessage = lpMsg;
288 data.dwMessageSize = dwMsgSize;
289 data.bSystemMessage = TRUE; /* Allow reply to be sent */
290 data.lpISP = This->dp2->spData.lpISP;
292 TRACE( "Asking for player id w/ Flags 0x%08x\n", lpMsgBody->Flags );
294 lpMsg = DP_MSG_ExpectReply( This, &data,
295 DPMSG_RELIABLE_API_TIMER,
296 DPMSGCMD_REQUESTPLAYERREPLY,
297 NULL, &lpMsg, &dwMsgSize );
300 /* Examine reply */
301 if( lpMsg )
303 *lpdpidAllocatedId = ((LPCDPSP_MSG_REQUESTPLAYERREPLY) lpMsg)->ID;
304 TRACE( "Received new id 0x%08x\n", *lpdpidAllocatedId );
306 else
308 ERR( "Didn't receive reply\n" );
309 hr = DPERR_GENERIC;
312 HeapFree( GetProcessHeap(), 0, lpMsg );
313 return hr;
316 HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer )
318 LPVOID lpMsg;
319 LPDPSP_MSG_ADDFORWARDREQUEST lpMsgBody;
320 DWORD dwMsgSize;
321 HRESULT hr = DP_OK;
323 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
325 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
327 lpMsgBody = (LPDPSP_MSG_ADDFORWARDREQUEST)( (LPBYTE)lpMsg +
328 This->dp2->spData.dwSPHeaderSize );
330 /* Compose dplay message envelope */
331 lpMsgBody->envelope.dwMagic = DPMSG_SIGNATURE;
332 lpMsgBody->envelope.wCommandId = DPMSGCMD_ADDFORWARDREQUEST;
333 lpMsgBody->envelope.wVersion = DX61AVERSION;
335 /* Compose body of message */
336 FIXME( "TODO\n" );
338 /* Send the message */
340 DPSP_SENDDATA data;
342 data.dwFlags = DPSEND_GUARANTEED;
343 data.idPlayerTo = 0; /* Name server */
344 data.idPlayerFrom = dpidServer; /* Sending from session server */
345 data.lpMessage = lpMsg;
346 data.dwMessageSize = dwMsgSize;
347 data.bSystemMessage = TRUE; /* Allow reply to be sent */
348 data.lpISP = This->dp2->spData.lpISP;
350 TRACE( "Sending forward player request with 0x%08x\n", dpidServer );
352 lpMsg = DP_MSG_ExpectReply( This, &data,
353 DPMSG_RELIABLE_API_TIMER,
354 DPMSGCMD_ADDFORWARD,
355 NULL, &lpMsg, &dwMsgSize );
358 /* Need to examine the data and extract the new player id */
359 if( lpMsg != NULL )
361 FIXME( "Name Table reply received: stub\n" );
364 return hr;
367 HRESULT DP_MSG_SendCreatePlayer( IDirectPlay2AImpl* This, lpPlayerData lpData )
369 LPBYTE lpMsg;
370 LPDPSP_MSG_CREATEPLAYER lpMsgBody;
371 DWORD dwMsgSize, dwWrapperSize;
372 HRESULT hr;
374 TRACE( "(%p)->(0x%08x)\n", This, lpData->dpid );
377 /* If the session supports multicast, wrap the message up into
378 * a DPSP_MSG_ASK4MULTICAST */
379 if ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER )
381 dwWrapperSize = sizeof(DPSP_MSG_ASK4MULTICAST);
383 else
385 dwWrapperSize = 0;
389 dwMsgSize = This->dp2->spData.dwSPHeaderSize +
390 dwWrapperSize +
391 sizeof(DPSP_MSG_CREATEPLAYER) +
392 256; /* Estimated max size for player data */
394 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
395 lpMsgBody = (LPDPSP_MSG_CREATEPLAYER)( lpMsg +
396 This->dp2->spData.dwSPHeaderSize +
397 dwWrapperSize );
400 /* Fill wrapper if needed */
401 if ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER )
403 LPDPSP_MSG_ASK4MULTICAST lpWrapper = (LPDPSP_MSG_ASK4MULTICAST) lpMsg;
405 lpWrapper->envelope.dwMagic = DPMSG_SIGNATURE;
406 lpWrapper->envelope.wCommandId = DPMSGCMD_CREATEPLAYER;
407 lpWrapper->envelope.wVersion = DX61AVERSION;
409 lpWrapper->GroupTo = 0; /*TODO*/
410 lpWrapper->PlayerFrom = lpData->dpid;
411 lpWrapper->MessageOffset = sizeof(DPSP_MSG_ASK4MULTICAST);
415 /* Compose dplay message envelope */
416 lpMsgBody->envelope.dwMagic = DPMSG_SIGNATURE;
417 lpMsgBody->envelope.wCommandId = DPMSGCMD_CREATEPLAYER;
418 lpMsgBody->envelope.wVersion = DX61AVERSION;
420 /* Compose body of message */
421 lpMsgBody->IDTo = 0; /* Name server */
422 lpMsgBody->PlayerID = lpData->dpid;
423 lpMsgBody->GroupID = 0; /* Ignored */
424 lpMsgBody->CreateOffset = sizeof(DPSP_MSG_CREATEPLAYER);
425 lpMsgBody->PasswordOffset = 0; /* Ignored */
427 /* Add PlayerInfo and recalculation of exact message size */
428 dwMsgSize -= 256; /* We estimated 256 */
429 dwMsgSize += DP_MSG_FillPackedPlayer(
430 This,
431 (LPDPLAYI_PACKEDPLAYER)(((LPBYTE) lpMsgBody) + lpMsgBody->CreateOffset ),
432 lpData, FALSE, TRUE );
435 /* If the session supports multicast, send message to the game host */
436 if ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER )
438 DPSP_SENDDATA sendData;
439 sendData.dwFlags = DPSEND_GUARANTEED;
440 sendData.idPlayerTo = 0; /* Name server */
441 sendData.idPlayerFrom = lpData->dpid;
442 sendData.lpMessage = lpMsg;
443 sendData.dwMessageSize = dwMsgSize;
444 sendData.bSystemMessage = TRUE; /* Allow reply to be sent */
445 sendData.lpISP = This->dp2->spData.lpISP;
447 hr = (*This->dp2->spData.lpCB->Send)( &sendData );
449 /* Otherwise, send the message to each player in the session */
450 else
452 lpPlayerList lpPList;
453 DPSP_SENDDATA sendData;
454 sendData.dwFlags = DPSEND_GUARANTEED;
455 sendData.idPlayerFrom = lpData->dpid;
456 sendData.lpMessage = lpMsg;
457 sendData.dwMessageSize = dwMsgSize;
458 sendData.bSystemMessage = TRUE;
459 sendData.lpISP = This->dp2->spData.lpISP;
461 if ( (lpPList = DPQ_FIRST( This->dp2->lpSysGroup->players )) )
465 if ( ( lpPList->lpPData->dwFlags & DPLAYI_PLAYER_SYSPLAYER ) &&
466 ( ~lpPList->lpPData->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL ) )
468 sendData.idPlayerTo = lpPList->lpPData->dpid;
469 hr = (*This->dp2->spData.lpCB->Send)( &sendData );
470 if ( FAILED(hr) )
472 ERR( "Failed to send message to 0x%08x\n", sendData.idPlayerTo );
476 while( (lpPList = DPQ_NEXT( lpPList->players )) );
481 HeapFree( GetProcessHeap(), 0, lpMsg );
482 return hr;
485 /* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
486 * not seem to offer any way of uniquely differentiating between replies of the same type
487 * relative to the request sent. There is an implicit assumption that there will be no
488 * ordering issues on sends and receives from the opposite machine. No wonder MS is not
489 * a networking company.
491 static
492 LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA lpData,
493 DWORD dwWaitTime, WORD wReplyCommandId,
494 LPVOID* lplpReplyHdr, LPVOID* lplpReplyMsg,
495 LPDWORD lpdwMsgBodySize )
497 HRESULT hr;
498 HANDLE hMsgReceipt;
499 DP_MSG_REPLY_STRUCT_LIST replyStructList;
500 DWORD dwWaitReturn;
501 WORD wCommandId;
503 /* Setup for receipt */
504 hMsgReceipt = DP_MSG_BuildAndLinkReplyStruct( This, &replyStructList,
505 wReplyCommandId );
507 wCommandId = ((LPCDPSP_MSG_ENVELOPE)
508 ( ((LPBYTE) lpData->lpMessage) +
509 This->dp2->spData.dwSPHeaderSize ))->wCommandId;
510 TRACE( "Sending cmd 0x%x and expecting cmd 0x%x in reply within %u ticks\n",
511 wCommandId, wReplyCommandId, dwWaitTime );
512 hr = (*This->dp2->spData.lpCB->Send)( lpData );
514 if( FAILED(hr) )
516 ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr ) );
517 return NULL;
520 /* The reply message will trigger the hMsgReceipt event effectively switching
521 * control back to this thread. See DP_MSG_ReplyReceived.
523 dwWaitReturn = WaitForSingleObject( hMsgReceipt, dwWaitTime );
524 if( dwWaitReturn != WAIT_OBJECT_0 )
526 ERR( "Wait failed 0x%08x\n", dwWaitReturn );
527 return NULL;
530 /* Clean Up */
531 return DP_MSG_CleanReplyStruct( &replyStructList, lplpReplyHdr,
532 lplpReplyMsg, lpdwMsgBodySize );
535 /* Determine if there is a matching request for this incoming message and then copy
536 * all important data. It is quite silly to have to copy the message, but the documents
537 * indicate that a copy is taken. Silly really.
539 BOOL DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId,
540 LPCVOID lpcMsgHdr, LPCVOID lpcMsgBody,
541 DWORD dwMsgBodySize )
543 LPDP_MSG_REPLY_STRUCT_LIST lpReplyList;
545 /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to
546 * avoid problems.
548 EnterCriticalSection( &This->unk->DP_lock );
549 DPQ_REMOVE_ENTRY( This->dp2->replysExpected, replysExpected, replyExpected.wExpectedReply,
550 ==, wCommandId, lpReplyList );
551 LeaveCriticalSection( &This->unk->DP_lock );
553 if( lpReplyList == NULL )
555 TRACE( "No receipt event set for cmd 0x%x\n", wCommandId );
556 return FALSE;
559 lpReplyList->replyExpected.dwMsgBodySize = dwMsgBodySize;
560 /* TODO: Can we avoid theese allocations? */
561 lpReplyList->replyExpected.lpReplyHdr = HeapAlloc( GetProcessHeap(),
562 HEAP_ZERO_MEMORY,
563 This->dp2->spData.dwSPHeaderSize );
564 lpReplyList->replyExpected.lpReplyMsg = HeapAlloc( GetProcessHeap(),
565 HEAP_ZERO_MEMORY,
566 dwMsgBodySize );
567 CopyMemory( lpReplyList->replyExpected.lpReplyHdr,
568 lpcMsgHdr, This->dp2->spData.dwSPHeaderSize );
569 CopyMemory( lpReplyList->replyExpected.lpReplyMsg,
570 lpcMsgBody, dwMsgBodySize );
572 /* Signal the thread which sent the message that it has a reply */
573 SetEvent( lpReplyList->replyExpected.hReceipt );
575 return TRUE;
578 DWORD DP_CopyString( LPVOID destination, LPVOID source, BOOL bAnsi )
580 /* Copies an ASCII string (bAnsi=TRUE) or a wide string (bAnsi=FALSE)
581 * from source to the previously allocated destination buffer.
582 * The destination string will be always wide.
583 * If destination is NULL, doesn't perform the copy but the
584 * returned size is still correct.
586 * Returns: The size in bytes of the written string. */
588 DWORD dwLength;
590 if ( source == NULL )
591 return 0;
593 if ( bAnsi )
595 dwLength = MultiByteToWideChar( CP_ACP, 0, (LPSTR) source, -1, NULL, 0 );
596 if ( destination )
597 MultiByteToWideChar( CP_ACP, 0, (LPSTR) source, -1,
598 (LPWSTR) destination, dwLength );
600 else
602 dwLength = lstrlenW( (LPWSTR) source ) + 1;
603 if ( destination )
604 CopyMemory( destination, source, dwLength );
607 return dwLength * sizeof(WCHAR);
610 static DWORD DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl* lpDP,
611 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer,
612 LPVOID lpData,
613 BOOL bIsGroup,
614 BOOL bAnsi )
616 /* Fills lpPackedPlayer with the information in lpData.
617 * lpData can be a player or a group.
618 * If lpPackedPlayer is NULL just returns the size
619 * needed to pack the player.
621 * Returns: the size of the written data in bytes */
623 #define PLAYER_OR_GROUP( bIsGroup, lpData, field ) \
624 ( bIsGroup \
625 ? ((lpGroupData) lpData)->field \
626 : ((lpPlayerData) lpData)->field )
628 DWORD offset, length, size;
629 LPVOID playerSPData;
631 if ( lpPackedPlayer == NULL )
633 size = sizeof(DPLAYI_SUPERPACKEDPLAYER); /* Fixed data */
634 size += DP_CopyString( NULL, /* Short name */
635 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
636 bAnsi );
637 size += DP_CopyString( NULL, /* Long name */
638 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
639 bAnsi );
640 /* Player data length */
641 /* Player data */
642 /* SP data length */
643 /* SP data */
645 if ( bIsGroup )
647 /* Player count */
648 /* Player IDs */
649 /* ParentID */
650 /* Shortcut ID Count */
651 /* Shortcut IDs */
653 return size;
656 lpPackedPlayer->Size = sizeof(DPLAYI_SUPERPACKEDPLAYER);
658 lpPackedPlayer->Flags = 0x000000FF & PLAYER_OR_GROUP( bIsGroup, lpData, dwFlags );
659 lpPackedPlayer->ID = PLAYER_OR_GROUP( bIsGroup, lpData, dpid );
661 if ( lpPackedPlayer->Flags & DPLAYI_PLAYER_SYSPLAYER )
663 lpPackedPlayer->VersionOrSystemPlayerID = DX61AVERSION;
665 else
667 lpPackedPlayer->VersionOrSystemPlayerID =
668 DPQ_FIRST( lpDP->dp2->lpSysGroup->players )->lpPData->dpid;
671 offset = lpPackedPlayer->Size;
673 /* Short name */
674 length = DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
675 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
676 bAnsi );
677 if ( length )
678 lpPackedPlayer->PlayerInfoMask |= SPP_SN;
679 offset += length;
681 /* Long name */
682 length = DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
683 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
684 bAnsi );
685 if ( length )
686 lpPackedPlayer->PlayerInfoMask |= SPP_LN;
687 offset += length;
689 /* Player data */
690 length = PLAYER_OR_GROUP( bIsGroup, lpData, dwRemoteDataSize);
691 if ( length )
693 size = spp_get_optimum_size( length );
694 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_PD_OFFSET );
695 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, &length, size );
696 offset += size;
698 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
699 PLAYER_OR_GROUP( bIsGroup, lpData, lpRemoteData ),
700 length );
701 offset += length;
704 /* Service provider data */
705 IDirectPlaySP_GetSPPlayerData( lpDP->dp2->spData.lpISP, lpPackedPlayer->ID,
706 &playerSPData, &length, DPGET_REMOTE );
707 if ( length )
709 size = spp_get_optimum_size( length );
710 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SL_OFFSET );
711 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, &length, size );
712 offset += size;
713 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, playerSPData, length );
714 offset += length;
717 if ( bIsGroup )
719 /* Player IDs */
720 if( !DPQ_IS_EMPTY( ((lpGroupData)lpData)->players ) )
722 DWORD player_count, offset_PC;
723 lpPlayerList lpPList;
725 offset_PC = offset; /* Space for PlayerCount */
726 offset += 4;
727 player_count = 0;
729 /* PlayerIDs */
730 if ( (lpPList = DPQ_FIRST( ((lpGroupData)lpData)->players )) )
734 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
735 &lpPList->lpPData->dpid,
736 sizeof(DPID) );
737 offset += sizeof(DPID);
738 player_count++;
740 while( (lpPList = DPQ_NEXT( lpPList->players )) );
743 /* PlayerCount */
744 size = spp_get_optimum_size( player_count );
745 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_PC_OFFSET );
747 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset_PC, &player_count, size );
750 /* ParentID */
751 if ( ((lpGroupData)lpData)->parent )
753 lpPackedPlayer->PlayerInfoMask |= SPP_PI;
754 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
755 &((lpGroupData)lpData)->parent,
756 sizeof(DWORD) );
757 offset += sizeof(DWORD);
760 /* Shortcut IDs */
761 /*size = spp_get_optimum_size( ___ );
762 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SC_OFFSET );*/
763 FIXME( "TODO: Add shortcut IDs\n" );
766 return offset;
769 static DWORD DP_MSG_FillPackedPlayer( IDirectPlay2Impl* lpDP,
770 LPDPLAYI_PACKEDPLAYER lpPackedPlayer,
771 LPVOID lpData,
772 BOOL bIsGroup,
773 BOOL bAnsi )
775 /* Fills lpPackedPlayer with the information in lpData.
776 * lpData can be a player or a group.
777 * If lpPackedPlayer is NULL just returns the size
778 * needed to pack the player.
780 * Returns: the size of the written data in bytes */
782 LPVOID playerSPData;
783 DWORD offset;
785 if ( lpPackedPlayer == NULL )
787 DWORD size;
788 size = sizeof(DPLAYI_PACKEDPLAYER); /* Fixed data */
789 size += DP_CopyString( NULL, /* Short name */
790 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
791 bAnsi );
792 size += DP_CopyString( NULL, /* Long name */
793 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
794 bAnsi );
795 /* SP data */
796 /* Player data */
798 if ( bIsGroup )
800 /* Player IDs */
802 return size;
805 lpPackedPlayer->SystemPlayerID =
806 DPQ_FIRST( lpDP->dp2->lpSysGroup->players )->lpPData->dpid;
807 lpPackedPlayer->FixedSize = sizeof(DPLAYI_PACKEDPLAYER);
808 lpPackedPlayer->PlayerVersion = DX61AVERSION;
810 lpPackedPlayer->Flags = 0x000000FF & PLAYER_OR_GROUP( bIsGroup, lpData, dwFlags );
811 lpPackedPlayer->PlayerID = PLAYER_OR_GROUP( bIsGroup, lpData, dpid );
812 lpPackedPlayer->ParentID = ( bIsGroup
813 ? ((lpGroupData)lpData)->parent
814 : 0 );
816 offset = lpPackedPlayer->FixedSize;
818 /* Short name */
819 lpPackedPlayer->ShortNameLength =
820 DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
821 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
822 bAnsi );
823 offset += lpPackedPlayer->ShortNameLength;
825 /* Long name */
826 lpPackedPlayer->LongNameLength =
827 DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
828 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
829 bAnsi );
830 offset += lpPackedPlayer->LongNameLength;
832 /* Service provider data */
833 IDirectPlaySP_GetSPPlayerData( lpDP->dp2->spData.lpISP,
834 lpPackedPlayer->PlayerID,
835 &playerSPData,
836 &lpPackedPlayer->ServiceProviderDataSize,
837 DPGET_REMOTE );
838 if ( lpPackedPlayer->ServiceProviderDataSize )
840 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, playerSPData,
841 lpPackedPlayer->ServiceProviderDataSize );
842 offset += lpPackedPlayer->ServiceProviderDataSize;
845 /* Player data */
846 lpPackedPlayer->PlayerDataSize = PLAYER_OR_GROUP( bIsGroup, lpData, dwRemoteDataSize );
847 if ( lpPackedPlayer->PlayerDataSize )
849 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
850 PLAYER_OR_GROUP( bIsGroup, lpData, lpRemoteData ),
851 lpPackedPlayer->PlayerDataSize );
852 offset += lpPackedPlayer->PlayerDataSize;
855 if ( bIsGroup )
857 lpPlayerList lpPList;
859 /* Player IDs */
860 lpPackedPlayer->NumberOfPlayers = 0;
862 if ( (lpPList = DPQ_FIRST( ((lpGroupData)lpData)->players )) )
866 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
867 &lpPList->lpPData->dpid,
868 sizeof(DPID) );
869 offset += sizeof(DPID);
870 lpPackedPlayer->NumberOfPlayers++;
872 while( (lpPList = DPQ_NEXT( lpPList->players )) );
877 /* Total size */
878 lpPackedPlayer->Size = offset;
880 return lpPackedPlayer->Size;
883 void DP_MSG_ReplyToEnumPlayersRequest( IDirectPlay2Impl* lpDP,
884 LPVOID* lplpReply,
885 LPDWORD lpdwMsgSize )
887 /* Depending on the type of session, builds either a EnumPlayers
888 reply or a SuperEnumPlayers reply, and places it in lplpReply */
890 /* TODO: Find size to allocate *lplpReply
891 * Check if we're releasing that memory */
893 LPDPSP_MSG_ENUMPLAYERSREPLY lpReply; /* Also valid in the SUPER case */
894 lpPlayerList lpPList;
895 lpGroupList lpGList;
896 DWORD offset;
897 BOOL bAnsi = TRUE; /* FIXME: This needs to be in the DPLAY interface */
900 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 1024 );
901 lpReply = (LPDPSP_MSG_ENUMPLAYERSREPLY)( (LPBYTE)(*lplpReply) +
902 lpDP->dp2->spData.dwSPHeaderSize );
904 lpReply->envelope.dwMagic = DPMSG_SIGNATURE;
905 lpReply->envelope.wVersion = DX61AVERSION;
907 if ( lpDP->dp2->lpSessionDesc->dwFlags & DPSESSION_CLIENTSERVER )
909 lpReply->envelope.wCommandId = DPMSGCMD_ENUMPLAYERSREPLY;
911 else
913 lpReply->envelope.wCommandId = DPMSGCMD_SUPERENUMPLAYERSREPLY;
917 /* Session description */
918 lpReply->DescriptionOffset = ( sizeof(DPSP_MSG_ENUMPLAYERSREPLY) -
919 sizeof(DPSESSIONDESC2) );
920 CopyMemory( &lpReply->DPSessionDesc, lpDP->dp2->lpSessionDesc,
921 sizeof(DPSESSIONDESC2) );
923 offset = sizeof(DPSP_MSG_ENUMPLAYERSREPLY);
925 /* Session name */
926 if ( lpDP->dp2->lpSessionDesc->lpszSessionName )
928 lpReply->NameOffset = offset;
929 offset += DP_CopyString( ((LPBYTE) lpReply) + offset,
930 lpDP->dp2->lpSessionDesc->lpszSessionName,
931 bAnsi );
934 /* Session password */
935 if ( lpDP->dp2->lpSessionDesc->lpszPassword )
937 lpReply->PasswordOffset = offset;
938 offset += DP_CopyString( ((LPBYTE) lpReply) + offset,
939 lpDP->dp2->lpSessionDesc->lpszPassword,
940 bAnsi );
943 /* Populate PlayerInfo list */
945 /* - Players */
946 if ( (lpPList = DPQ_FIRST( lpDP->dp2->lpSysGroup->players )) )
950 if ( lpReply->envelope.wCommandId == DPMSGCMD_SUPERENUMPLAYERSREPLY )
952 offset += DP_MSG_FillSuperPackedPlayer(
953 lpDP, (LPDPLAYI_SUPERPACKEDPLAYER)( ((LPBYTE)lpReply) + offset ),
954 lpPList->lpPData, FALSE, bAnsi );
956 else
958 offset += DP_MSG_FillPackedPlayer(
959 lpDP, (LPDPLAYI_PACKEDPLAYER)( ((LPBYTE)lpReply) + offset ),
960 lpPList->lpPData, FALSE, bAnsi );
963 lpReply->PlayerCount++;
965 while( (lpPList = DPQ_NEXT( lpPList->players )) );
968 /* - Groups */
969 if ( (lpGList = DPQ_FIRST( lpDP->dp2->lpSysGroup->groups )) )
973 if ( lpReply->envelope.wCommandId == DPMSGCMD_SUPERENUMPLAYERSREPLY )
975 offset += DP_MSG_FillSuperPackedPlayer(
976 lpDP, (LPDPLAYI_SUPERPACKEDPLAYER)( ((LPBYTE)lpReply) + offset ),
977 lpGList->lpGData, TRUE, bAnsi );
979 else
981 offset += DP_MSG_FillPackedPlayer(
982 lpDP, (LPDPLAYI_PACKEDPLAYER)( ((LPBYTE)lpReply) + offset ),
983 lpGList->lpGData, TRUE, bAnsi );
986 lpReply->GroupCount++;
988 while( (lpGList = DPQ_NEXT( lpGList->groups )) );
991 if ( lpReply->envelope.wCommandId == DPMSGCMD_SUPERENUMPLAYERSREPLY )
993 /* - Groups with shortcuts */
994 FIXME( "TODO: Add shortcut IDs\n" );
997 *lpdwMsgSize = lpDP->dp2->spData.dwSPHeaderSize + offset;