ReactOS  0.4.10-dev-479-g13a3cf0
dplay.c
Go to the documentation of this file.
1 /* Direct Play 2,3,4 Implementation
2  *
3  * Copyright 1998,1999,2000,2001 - Peter Hunnisett
4  *
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.
9  *
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.
14  *
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
18  */
19 
20 #define COBJMACROS
21 #include "config.h"
22 #include "wine/port.h"
23 
24 #include <stdarg.h>
25 #include <string.h>
26 
27 #define NONAMELESSUNION
28 
29 #include "windef.h"
30 #include "winerror.h"
31 #include "winbase.h"
32 #include "winnt.h"
33 #include "winreg.h"
34 #include "winnls.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
37 
38 #include "dplayx_global.h"
39 #include "name_server.h"
40 #include "dplayx_queue.h"
41 #include "wine/dplaysp.h"
42 #include "dplay_global.h"
43 
45 
46 /* FIXME: Should this be externed? */
48 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
49  LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
50 
51 
52 /* Local function prototypes */
53 static lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid );
54 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
55 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
56  LPVOID lpData, DWORD dwDataSize );
57 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
59  DWORD dwPlayerType,
61  DWORD dwFlags,
62  LPVOID lpContext );
63 static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid );
64 
65 /* Helper methods for player/group interfaces */
66 static HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
67  DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
68 static HRESULT DP_SP_SendEx( IDirectPlayImpl *This, DWORD dwFlags, void *lpData, DWORD dwDataSize,
69  DWORD dwPriority, DWORD dwTimeout, void *lpContext, DWORD *lpdwMsgID );
70 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
71  LPDWORD lpdwBufSize );
72 
73 static DPID DP_GetRemoteNextObjectId(void);
74 
75 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
76 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
77  LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
78 
79 
80 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
81 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
82  we don't have to change much */
83 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
84 
85 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
86 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
87 
88 /* Strip out all dwFlags values for CREATEPLAYER msg */
89 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
90 
91 static LONG kludgePlayerGroupId = 1000;
92 
93 
94 static inline IDirectPlayImpl *impl_from_IDirectPlay( IDirectPlay *iface )
95 {
96  return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay_iface );
97 }
98 
99 static inline IDirectPlayImpl *impl_from_IDirectPlay2( IDirectPlay2 *iface )
100 {
101  return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay2_iface );
102 }
103 
105 {
106  return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay2A_iface );
107 }
108 
110 {
111  return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay3A_iface );
112 }
113 
114 static inline IDirectPlayImpl *impl_from_IDirectPlay3( IDirectPlay3 *iface )
115 {
116  return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay3_iface );
117 }
118 
120 {
121  return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4A_iface );
122 }
123 
124 static inline IDirectPlayImpl *impl_from_IDirectPlay4( IDirectPlay4 *iface )
125 {
126  return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4_iface );
127 }
128 
130 {
131  IDirectPlayImpl *This = lpDP;
132 
133  This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
134  if ( This->dp2 == NULL )
135  {
136  return FALSE;
137  }
138 
139  This->dp2->bConnectionOpen = FALSE;
140 
142  This->dp2->dwEnumSessionLock = 0;
143 
144  This->dp2->bHostInterface = FALSE;
145 
146  DPQ_INIT(This->dp2->receiveMsgs);
147  DPQ_INIT(This->dp2->sendMsgs);
148  DPQ_INIT(This->dp2->repliesExpected);
149 
151  {
152  /* FIXME: Memory leak */
153  return FALSE;
154  }
155 
156  /* Provide an initial session desc with nothing in it */
159  sizeof( *This->dp2->lpSessionDesc ) );
160  if( This->dp2->lpSessionDesc == NULL )
161  {
162  /* FIXME: Memory leak */
163  return FALSE;
164  }
165  This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
166 
167  /* We are emulating a dp 6 implementation */
169 
171  sizeof( *This->dp2->spData.lpCB ) );
172  This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
174 
175  /* This is the pointer to the service provider */
176  if ( FAILED( dplaysp_create( &IID_IDirectPlaySP, (void**)&This->dp2->spData.lpISP, This ) ) )
177  {
178  /* FIXME: Memory leak */
179  return FALSE;
180  }
181 
182  /* Setup lobby provider information */
185  sizeof( *This->dp2->dplspData.lpCB ) );
186  This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
187 
188  if( FAILED( dplobbysp_create( &IID_IDPLobbySP, (void**)&This->dp2->dplspData.lpISP, This ) )
189  )
190  {
191  /* FIXME: Memory leak */
192  return FALSE;
193  }
194 
195  return TRUE;
196 }
197 
198 /* Definition of the global function in dplayx_queue.h. #
199  * FIXME: Would it be better to have a dplayx_queue.c for this function? */
200 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
201 {
202  HeapFree( GetProcessHeap(), 0, elem );
203 }
204 
206 {
207  IDirectPlayImpl *This = lpDP;
208 
210  {
213  }
214 
215  /* Finish with the SP - have it shutdown */
216  if( This->dp2->spData.lpCB->ShutdownEx )
217  {
219 
220  TRACE( "Calling SP ShutdownEx\n" );
221 
222  data.lpISP = This->dp2->spData.lpISP;
223 
224  (*This->dp2->spData.lpCB->ShutdownEx)( &data );
225  }
226  else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
227  {
228  TRACE( "Calling obsolete SP Shutdown\n" );
229  (*This->dp2->spData.lpCB->Shutdown)();
230  }
231 
232  /* Unload the SP (if it exists) */
233  if( This->dp2->hServiceProvider != 0 )
234  {
235  FreeLibrary( This->dp2->hServiceProvider );
236  }
237 
238  /* Unload the Lobby Provider (if it exists) */
239  if( This->dp2->hDPLobbyProvider != 0 )
240  {
241  FreeLibrary( This->dp2->hDPLobbyProvider );
242  }
243 
244  /* FIXME: Need to delete receive and send msgs queue contents */
245 
247 
248  HeapFree( GetProcessHeap(), 0, This->dp2->dplspData.lpCB);
249  HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
250 
252 
253  /* Delete the contents */
254  HeapFree( GetProcessHeap(), 0, This->dp2 );
255 
256  return TRUE;
257 }
258 
260 {
261  DP_DestroyDirectPlay2( obj );
262  obj->lock.DebugInfo->Spare[0] = 0;
263  DeleteCriticalSection( &obj->lock );
264  HeapFree( GetProcessHeap(), 0, obj );
265 }
266 
267 static inline DPID DP_NextObjectId(void)
268 {
270 }
271 
272 /* *lplpReply will be non NULL iff there is something to reply */
273 HRESULT DP_HandleMessage( IDirectPlayImpl *This, const void *lpcMessageBody,
274  DWORD dwMessageBodySize, const void *lpcMessageHeader, WORD wCommandId, WORD wVersion,
275  void **lplpReply, DWORD *lpdwMsgSize )
276 {
277  TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
278  This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
279  wVersion );
280 
281  switch( wCommandId )
282  {
283  /* Name server needs to handle this request */
285  /* Reply expected */
286  NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
287  break;
288 
289  /* Name server needs to handle this request */
291  /* No reply expected */
292  NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
293  This->dp2->spData.dwSPHeaderSize,
294  lpcMessageBody,
295  This->dp2->lpNameServerData );
296  break;
297 
299  {
300  LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
301 
302  LPDPMSG_NEWPLAYERIDREPLY lpReply;
303 
304  *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
305 
306  *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
307 
308  FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
309  lpcMsg->dwFlags );
310 
311  /* Setup the reply */
312  lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
313  This->dp2->spData.dwSPHeaderSize );
314 
317  lpReply->envelope.wVersion = DPMSGVER_DP6;
318 
319  lpReply->dpidNewPlayerId = DP_NextObjectId();
320 
321  TRACE( "Allocating new playerid 0x%08x from remote request\n",
322  lpReply->dpidNewPlayerId );
323  break;
324  }
325 
328  DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
329  break;
330 
332  TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
333  NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
334  DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
335 
337  TRACE( "Sending message to self to get my addr\n" );
338  DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
339  break;
340 
342  DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
343  break;
344 
345  default:
346  FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
347  DebugBreak();
348  break;
349  }
350 
351  /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
352 
353  return DP_OK;
354 }
355 
356 
357 static HRESULT WINAPI IDirectPlayImpl_QueryInterface( IDirectPlay *iface, REFIID riid, void **ppv )
358 {
359  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
360  return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
361 }
362 
363 static ULONG WINAPI IDirectPlayImpl_AddRef( IDirectPlay *iface )
364 {
365  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
366  ULONG ref = InterlockedIncrement( &This->ref );
367 
368  TRACE( "(%p) ref=%d\n", This, ref );
369 
370  if ( ref == 1 )
372 
373  return ref;
374 }
375 
376 static ULONG WINAPI IDirectPlayImpl_Release( IDirectPlay *iface )
377 {
378  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
379  ULONG ref = InterlockedDecrement( &This->ref );
380 
381  TRACE( "(%p) ref=%d\n", This, ref );
382 
383  if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
384  dplay_destroy( This );
385 
386  return ref;
387 }
388 
390  DPID player )
391 {
392  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
393  FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, player );
394  return E_NOTIMPL;
395 }
396 
397 static HRESULT WINAPI IDirectPlayImpl_Close( IDirectPlay *iface )
398 {
399  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
400  FIXME( "(%p): stub\n", This );
401  return E_NOTIMPL;
402 }
403 
404 static HRESULT WINAPI IDirectPlayImpl_CreatePlayer( IDirectPlay *iface, DPID *player,
405  LPSTR name, LPSTR fullname, HANDLE *event )
406 {
407  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
408  FIXME( "(%p)->(%p,%s,%s,%p): stub\n", This, player, debugstr_a( name ), debugstr_a( fullname ),
409  event );
410  return E_NOTIMPL;
411 }
412 
414  LPSTR fullname )
415 {
416  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
417  FIXME( "(%p)->(%p,%s,%s): stub\n", This, group, debugstr_a( name ), debugstr_a( fullname ) );
418  return E_NOTIMPL;
419 }
420 
422  DPID player )
423 {
424  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
425  FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, player );
426  return E_NOTIMPL;
427 }
428 
429 static HRESULT WINAPI IDirectPlayImpl_DestroyPlayer( IDirectPlay *iface, DPID player )
430 {
431  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
432  FIXME( "(%p)->(0x%08x): stub\n", This, player );
433  return E_NOTIMPL;
434 }
435 
436 static HRESULT WINAPI IDirectPlayImpl_DestroyGroup( IDirectPlay *iface, DPID group )
437 {
438  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
439  FIXME( "(%p)->(0x%08x): stub\n", This, group );
440  return E_NOTIMPL;
441 }
442 
444 {
445  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
446  FIXME( "(%p)->(%d): stub\n", This, enable );
447  return E_NOTIMPL;
448 }
449 
451  LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
452 {
453  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
454  FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, group, enumplayercb, context, flags );
455  return E_NOTIMPL;
456 }
457 
458 static HRESULT WINAPI IDirectPlayImpl_EnumGroups( IDirectPlay *iface, DWORD session,
459  LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
460 {
461  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
462  FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, session, enumplayercb, context, flags );
463  return E_NOTIMPL;
464 }
465 
466 static HRESULT WINAPI IDirectPlayImpl_EnumPlayers( IDirectPlay *iface, DWORD session,
467  LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
468 {
469  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
470  FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, session, enumplayercb, context, flags );
471  return E_NOTIMPL;
472 }
473 
474 static HRESULT WINAPI IDirectPlayImpl_EnumSessions( IDirectPlay *iface, DPSESSIONDESC *sdesc,
475  DWORD timeout, LPDPENUMSESSIONSCALLBACK enumsessioncb, void *context, DWORD flags )
476 {
477  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
478  FIXME( "(%p)->(%p,%u,%p,%p,0x%08x): stub\n", This, sdesc, timeout, enumsessioncb, context,
479  flags );
480  return E_NOTIMPL;
481 }
482 
483 static HRESULT WINAPI IDirectPlayImpl_GetCaps( IDirectPlay *iface, DPCAPS *caps )
484 {
485  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
486  FIXME( "(%p)->(%p): stub\n", This, caps );
487  return E_NOTIMPL;
488 }
489 
490 static HRESULT WINAPI IDirectPlayImpl_GetMessageCount( IDirectPlay *iface, DPID player,
491  DWORD *count )
492 {
493  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
494  FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, count );
495  return E_NOTIMPL;
496 }
497 
498 static HRESULT WINAPI IDirectPlayImpl_GetPlayerCaps( IDirectPlay *iface, DPID player, DPCAPS *caps )
499 {
500  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
501  FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, caps );
502  return E_NOTIMPL;
503 }
504 
505 static HRESULT WINAPI IDirectPlayImpl_GetPlayerName( IDirectPlay *iface, DPID player, LPSTR name,
506  DWORD *size_name, LPSTR fullname, DWORD *size_fullname )
507 {
508  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
509  FIXME( "(%p)->(0x%08x,%p,%p,%p,%p): stub\n", This, player, name, size_name, fullname,
510  size_fullname );
511  return E_NOTIMPL;
512 }
513 
514 static HRESULT WINAPI IDirectPlayImpl_Initialize( IDirectPlay *iface, GUID *guid )
515 {
516  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
517  FIXME( "(%p)->(%p): stub\n", This, guid );
518  return E_NOTIMPL;
519 }
520 
521 static HRESULT WINAPI IDirectPlayImpl_Open( IDirectPlay *iface, DPSESSIONDESC *sdesc )
522 {
523  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
524  FIXME( "(%p)->(%p): stub\n", This, sdesc );
525  return E_NOTIMPL;
526 }
527 
528 static HRESULT WINAPI IDirectPlayImpl_Receive( IDirectPlay *iface, DPID *from, DPID *to,
529  DWORD flags, void *data, DWORD *size )
530 {
531  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
532  FIXME( "(%p)->(%p,%p,0x%08x,%p,%p): stub\n", This, from, to, flags, data, size );
533  return E_NOTIMPL;
534 }
535 
537 {
538  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
539  FIXME( "(%p)->(%p): stub\n", This, reserved );
540  return E_NOTIMPL;
541 }
542 
543 static HRESULT WINAPI IDirectPlayImpl_Send( IDirectPlay *iface, DPID from, DPID to, DWORD flags,
544  void *data, DWORD size )
545 {
546  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
547  FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%u): stub\n", This, from, to, flags, data, size );
548  return E_NOTIMPL;
549 }
550 
551 static HRESULT WINAPI IDirectPlayImpl_SetPlayerName( IDirectPlay *iface, DPID player, LPSTR name,
552  LPSTR fullname )
553 {
554  IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
555  FIXME( "(%p)->(0x%08x,%s,%s): stub\n", This, player, debugstr_a( name ),
556  debugstr_a ( fullname ) );
557  return E_NOTIMPL;
558 }
559 
560 static const IDirectPlayVtbl dp_vt =
561 {
587 };
588 
589 
591  void **ppv )
592 {
593  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
594  return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
595 }
596 
598  void **ppv )
599 {
600  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
601  return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
602 }
603 
605  void **ppv )
606 {
607  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
608  return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
609 }
610 
612  void **ppv )
613 {
614  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
615  return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
616 }
617 
619  void **ppv )
620 {
621  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
622  return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
623 }
624 
626  void **ppv )
627 {
628  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
629 
630  if ( IsEqualGUID( &IID_IUnknown, riid ) )
631  {
632  TRACE( "(%p)->(IID_IUnknown %p)\n", This, ppv );
633  *ppv = &This->IDirectPlay_iface;
634  }
635  else if ( IsEqualGUID( &IID_IDirectPlay, riid ) )
636  {
637  TRACE( "(%p)->(IID_IDirectPlay %p)\n", This, ppv );
638  *ppv = &This->IDirectPlay_iface;
639  }
640  else if ( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
641  {
642  TRACE( "(%p)->(IID_IDirectPlay2A %p)\n", This, ppv );
643  *ppv = &This->IDirectPlay2A_iface;
644  }
645  else if ( IsEqualGUID( &IID_IDirectPlay2, riid ) )
646  {
647  TRACE( "(%p)->(IID_IDirectPlay2 %p)\n", This, ppv );
648  *ppv = &This->IDirectPlay2_iface;
649  }
650  else if ( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
651  {
652  TRACE( "(%p)->(IID_IDirectPlay3A %p)\n", This, ppv );
653  *ppv = &This->IDirectPlay3A_iface;
654  }
655  else if ( IsEqualGUID( &IID_IDirectPlay3, riid ) )
656  {
657  TRACE( "(%p)->(IID_IDirectPlay3 %p)\n", This, ppv );
658  *ppv = &This->IDirectPlay3_iface;
659  }
660  else if ( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
661  {
662  TRACE( "(%p)->(IID_IDirectPlay4A %p)\n", This, ppv );
663  *ppv = &This->IDirectPlay4A_iface;
664  }
665  else if ( IsEqualGUID( &IID_IDirectPlay4, riid ) )
666  {
667  TRACE( "(%p)->(IID_IDirectPlay4 %p)\n", This, ppv );
668  *ppv = &This->IDirectPlay4_iface;
669  }
670  else
671  {
672  WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
673  *ppv = NULL;
674  return E_NOINTERFACE;
675  }
676 
677  IUnknown_AddRef((IUnknown*)*ppv);
678  return S_OK;
679 }
680 
682 {
683  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
684  ULONG ref = InterlockedIncrement( &This->ref2A );
685 
686  TRACE( "(%p) ref2A=%d\n", This, ref );
687 
688  if ( ref == 1 )
690 
691  return ref;
692 }
693 
694 static ULONG WINAPI IDirectPlay2Impl_AddRef( IDirectPlay2 *iface )
695 {
696  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
697  ULONG ref = InterlockedIncrement( &This->ref2 );
698 
699  TRACE( "(%p) ref2=%d\n", This, ref );
700 
701  if ( ref == 1 )
703 
704  return ref;
705 }
706 
708 {
709  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
710  ULONG ref = InterlockedIncrement( &This->ref3A );
711 
712  TRACE( "(%p) ref3A=%d\n", This, ref );
713 
714  if ( ref == 1 )
716 
717  return ref;
718 }
719 
720 static ULONG WINAPI IDirectPlay3Impl_AddRef( IDirectPlay3 *iface )
721 {
722  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
723  ULONG ref = InterlockedIncrement( &This->ref3 );
724 
725  TRACE( "(%p) ref3=%d\n", This, ref );
726 
727  if ( ref == 1 )
729 
730  return ref;
731 }
732 
734 {
735  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
736  ULONG ref = InterlockedIncrement( &This->ref4A );
737 
738  TRACE( "(%p) ref4A=%d\n", This, ref );
739 
740  if ( ref == 1 )
742 
743  return ref;
744 }
745 
746 static ULONG WINAPI IDirectPlay4Impl_AddRef(IDirectPlay4 *iface)
747 {
748  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
749  ULONG ref = InterlockedIncrement( &This->ref4 );
750 
751  TRACE( "(%p) ref4=%d\n", This, ref );
752 
753  if ( ref == 1 )
755 
756  return ref;
757 }
758 
760 {
761  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
762  ULONG ref = InterlockedDecrement( &This->ref2A );
763 
764  TRACE( "(%p) ref2A=%d\n", This, ref );
765 
766  if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
767  dplay_destroy( This );
768 
769  return ref;
770 }
771 
772 static ULONG WINAPI IDirectPlay2Impl_Release( IDirectPlay2 *iface )
773 {
774  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
775  ULONG ref = InterlockedDecrement( &This->ref2 );
776 
777  TRACE( "(%p) ref2=%d\n", This, ref );
778 
779  if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
780  dplay_destroy( This );
781 
782  return ref;
783 }
784 
786 {
787  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
788  ULONG ref = InterlockedDecrement( &This->ref3A );
789 
790  TRACE( "(%p) ref3A=%d\n", This, ref );
791 
792  if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
793  dplay_destroy( This );
794 
795  return ref;
796 }
797 
798 static ULONG WINAPI IDirectPlay3Impl_Release( IDirectPlay3 *iface )
799 {
800  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
801  ULONG ref = InterlockedDecrement( &This->ref3 );
802 
803  TRACE( "(%p) ref3=%d\n", This, ref );
804 
805  if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
806  dplay_destroy( This );
807 
808  return ref;
809 }
810 
812 {
813  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
814  ULONG ref = InterlockedDecrement( &This->ref4A );
815 
816  TRACE( "(%p) ref4A=%d\n", This, ref );
817 
818  if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
819  dplay_destroy( This );
820 
821  return ref;
822 }
823 
824 static ULONG WINAPI IDirectPlay4Impl_Release(IDirectPlay4 *iface)
825 {
826  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
827  ULONG ref = InterlockedDecrement( &This->ref4 );
828 
829  TRACE( "(%p) ref4=%d\n", This, ref );
830 
831  if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
832  dplay_destroy( This );
833 
834  return ref;
835 }
836 
838  DPID player )
839 {
840  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
841  return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4A_iface, group, player );
842 }
843 
845  DPID player )
846 {
847  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
848  return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
849 }
850 
852  DPID player )
853 {
854  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
855  return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
856 }
857 
859  DPID player )
860 {
861  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
862  return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
863 }
864 
866  DPID player )
867 {
868  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
869  return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
870 }
871 
873  DPID player )
874 {
875  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
876  lpGroupData gdata;
878  lpPlayerList newplist;
879 
880  TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
881 
882  if ( This->dp2->connectionInitialized == NO_PROVIDER )
883  return DPERR_UNINITIALIZED;
884 
885  /* Find the group */
886  if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
887  return DPERR_INVALIDGROUP;
888 
889  /* Find the player */
890  if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
891  return DPERR_INVALIDPLAYER;
892 
893  /* Create a player list (ie "shortcut" ) */
894  newplist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *newplist ) );
895  if ( !newplist )
896  return DPERR_CANTADDPLAYER;
897 
898  /* Add the shortcut */
899  plist->lpPData->uRef++;
900  newplist->lpPData = plist->lpPData;
901 
902  /* Add the player to the list of players for this group */
903  DPQ_INSERT(gdata->players, newplist, players);
904 
905  /* Let the SP know that we've added a player to the group */
906  if ( This->dp2->spData.lpCB->AddPlayerToGroup )
907  {
909 
910  TRACE( "Calling SP AddPlayerToGroup\n" );
911 
912  data.idPlayer = player;
913  data.idGroup = group;
914  data.lpISP = This->dp2->spData.lpISP;
915 
916  (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
917  }
918 
919  /* Inform all other peers of the addition of player to the group. If there are
920  * no peers keep this event quiet.
921  * Also, if this event was the result of another machine sending it to us,
922  * don't bother rebroadcasting it.
923  */
924  if ( This->dp2->lpSessionDesc &&
926  {
929 
930  msg.dpIdGroup = group;
931  msg.dpIdPlayer = player;
932 
933  /* FIXME: Correct to just use send effectively? */
934  /* FIXME: Should size include data w/ message or just message "header" */
935  /* FIXME: Check return code */
936  IDirectPlayX_SendEx( iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
937  0, 0, NULL, NULL );
938  }
939 
940  return DP_OK;
941 }
942 
944 {
945  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
946  return IDirectPlayX_Close( &This->IDirectPlay4A_iface );
947 }
948 
949 static HRESULT WINAPI IDirectPlay2Impl_Close( IDirectPlay2 *iface )
950 {
951  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
952  return IDirectPlayX_Close( &This->IDirectPlay4_iface );
953 }
954 
956 {
957  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
958  return IDirectPlayX_Close( &This->IDirectPlay4_iface );
959 }
960 
961 static HRESULT WINAPI IDirectPlay3Impl_Close( IDirectPlay3 *iface )
962 {
963  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
964  return IDirectPlayX_Close( &This->IDirectPlay4_iface );
965 }
966 
968 {
969  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
970  return IDirectPlayX_Close( &This->IDirectPlay4_iface);
971 }
972 
973 static HRESULT WINAPI IDirectPlay4Impl_Close( IDirectPlay4 *iface )
974 {
975  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
976  HRESULT hr = DP_OK;
977 
978  TRACE( "(%p)\n", This );
979 
980  /* FIXME: Need to find a new host I assume (how?) */
981  /* FIXME: Need to destroy all local groups */
982  /* FIXME: Need to migrate all remotely visible players to the new host */
983 
984  /* Invoke the SP callback to inform of session close */
985  if( This->dp2->spData.lpCB->CloseEx )
986  {
988 
989  TRACE( "Calling SP CloseEx\n" );
990  data.lpISP = This->dp2->spData.lpISP;
991  hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
992  }
993  else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
994  {
995  TRACE( "Calling SP Close (obsolete interface)\n" );
996  hr = (*This->dp2->spData.lpCB->Close)();
997  }
998 
999  return hr;
1000 }
1001 
1002 static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, const DPNAME *lpName,
1003  DWORD dwFlags, DPID idParent, BOOL bAnsi )
1004 {
1005  lpGroupData lpGData;
1006 
1007  /* Allocate the new space and add to end of high level group list */
1008  lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
1009 
1010  if( lpGData == NULL )
1011  {
1012  return NULL;
1013  }
1014 
1015  DPQ_INIT(lpGData->groups);
1016  DPQ_INIT(lpGData->players);
1017 
1018  /* Set the desired player ID - no sanity checking to see if it exists */
1019  lpGData->dpid = *lpid;
1020 
1021  DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
1022 
1023  /* FIXME: Should we check that the parent exists? */
1024  lpGData->parent = idParent;
1025 
1026  /* FIXME: Should we validate the dwFlags? */
1027  lpGData->dwFlags = dwFlags;
1028 
1029  TRACE( "Created group id 0x%08x\n", *lpid );
1030 
1031  return lpGData;
1032 }
1033 
1034 /* This method assumes that all links to it are already deleted */
1035 static void DP_DeleteGroup( IDirectPlayImpl *This, DPID dpid )
1036 {
1037  lpGroupList lpGList;
1038 
1039  TRACE( "(%p)->(0x%08x)\n", This, dpid );
1040 
1041  DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
1042 
1043  if( lpGList == NULL )
1044  {
1045  ERR( "DPID 0x%08x not found\n", dpid );
1046  return;
1047  }
1048 
1049  if( --(lpGList->lpGData->uRef) )
1050  {
1051  FIXME( "Why is this not the last reference to group?\n" );
1052  DebugBreak();
1053  }
1054 
1055  /* Delete player */
1056  DP_DeleteDPNameStruct( &lpGList->lpGData->name );
1057  HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
1058 
1059  /* Remove and Delete Player List object */
1060  HeapFree( GetProcessHeap(), 0, lpGList );
1061 
1062 }
1063 
1065 {
1066  lpGroupList lpGroups;
1067 
1068  TRACE( "(%p)->(0x%08x)\n", This, dpid );
1069 
1070  if( dpid == DPID_SYSTEM_GROUP )
1071  {
1072  return This->dp2->lpSysGroup;
1073  }
1074  else
1075  {
1076  DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
1077  }
1078 
1079  if( lpGroups == NULL )
1080  {
1081  return NULL;
1082  }
1083 
1084  return lpGroups->lpGData;
1085 }
1086 
1087 static HRESULT DP_IF_CreateGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidGroup,
1088  DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
1089 {
1090  lpGroupData lpGData;
1091 
1092  TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1093  This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1094  dwFlags, bAnsi );
1095 
1096  if( This->dp2->connectionInitialized == NO_PROVIDER )
1097  {
1098  return DPERR_UNINITIALIZED;
1099  }
1100 
1101  /* If the name is not specified, we must provide one */
1102  if( DPID_UNKNOWN == *lpidGroup )
1103  {
1104  /* If we are the name server, we decide on the group ids. If not, we
1105  * must ask for one before attempting a creation.
1106  */
1107  if( This->dp2->bHostInterface )
1108  {
1109  *lpidGroup = DP_NextObjectId();
1110  }
1111  else
1112  {
1113  *lpidGroup = DP_GetRemoteNextObjectId();
1114  }
1115  }
1116 
1117  lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1118  DPID_NOPARENT_GROUP, bAnsi );
1119 
1120  if( lpGData == NULL )
1121  {
1122  return DPERR_CANTADDPLAYER; /* yes player not group */
1123  }
1124 
1125  if( DPID_SYSTEM_GROUP == *lpidGroup )
1126  {
1127  This->dp2->lpSysGroup = lpGData;
1128  TRACE( "Inserting system group\n" );
1129  }
1130  else
1131  {
1132  /* Insert into the system group */
1133  lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1134  lpGroup->lpGData = lpGData;
1135 
1136  DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1137  }
1138 
1139  /* Something is now referencing this data */
1140  lpGData->uRef++;
1141 
1142  /* Set all the important stuff for the group */
1143  DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1144 
1145  /* FIXME: We should only create the system group if GetCaps returns
1146  * DPCAPS_GROUPOPTIMIZED.
1147  */
1148 
1149  /* Let the SP know that we've created this group */
1150  if( This->dp2->spData.lpCB->CreateGroup )
1151  {
1153  DWORD dwCreateFlags = 0;
1154 
1155  TRACE( "Calling SP CreateGroup\n" );
1156 
1157  if( *lpidGroup == DPID_NOPARENT_GROUP )
1158  dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1159 
1160  if( lpMsgHdr == NULL )
1161  dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1162 
1163  if( dwFlags & DPGROUP_HIDDEN )
1164  dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1165 
1166  data.idGroup = *lpidGroup;
1167  data.dwFlags = dwCreateFlags;
1168  data.lpSPMessageHeader = lpMsgHdr;
1169  data.lpISP = This->dp2->spData.lpISP;
1170 
1171  (*This->dp2->spData.lpCB->CreateGroup)( &data );
1172  }
1173 
1174  /* Inform all other peers of the creation of a new group. If there are
1175  * no peers keep this event quiet.
1176  * Also if this message was sent to us, don't rebroadcast.
1177  */
1178  if( ( lpMsgHdr == NULL ) &&
1179  This->dp2->lpSessionDesc &&
1181  {
1184 
1186  msg.dpId = *lpidGroup;
1187  msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1188  msg.lpData = lpData;
1189  msg.dwDataSize = dwDataSize;
1190  msg.dpnName = *lpGroupName;
1192  msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1193 
1194  /* FIXME: Correct to just use send effectively? */
1195  /* FIXME: Should size include data w/ message or just message "header" */
1196  /* FIXME: Check return code */
1198  sizeof( msg ), 0, 0, NULL, NULL );
1199  }
1200 
1201  return DP_OK;
1202 }
1203 
1205  DPNAME *name, void *data, DWORD size, DWORD flags )
1206 {
1207  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1208  return IDirectPlayX_CreateGroup( &This->IDirectPlay4A_iface, lpidGroup, name, data, size,
1209  flags );
1210 }
1211 
1212 static HRESULT WINAPI IDirectPlay2Impl_CreateGroup( IDirectPlay2 *iface, DPID *lpidGroup,
1213  DPNAME *name, void *data, DWORD size, DWORD flags )
1214 {
1215  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1216  return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, lpidGroup, name, data, size,
1217  flags );
1218 }
1219 
1221  DPNAME *name, void *data, DWORD size, DWORD flags )
1222 {
1223  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
1224  return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, group, name, data, size,
1225  flags );
1226 }
1227 
1228 static HRESULT WINAPI IDirectPlay3Impl_CreateGroup( IDirectPlay3 *iface, DPID *lpidGroup,
1229  DPNAME *name, void *data, DWORD size, DWORD flags )
1230 {
1231  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1232  return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, lpidGroup, name, data, size,
1233  flags );
1234 }
1235 
1237  DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1238 {
1239  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1240 
1241  *lpidGroup = DPID_UNKNOWN;
1242 
1243  return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
1244  TRUE );
1245 }
1246 
1247 static HRESULT WINAPI IDirectPlay4Impl_CreateGroup( IDirectPlay4 *iface, DPID *lpidGroup,
1248  DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1249 {
1250  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1251 
1252  *lpidGroup = DPID_UNKNOWN;
1253 
1254  return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
1255  FALSE );
1256 }
1257 
1258 
1259 static void
1261  LPVOID lpData, DWORD dwDataSize )
1262 {
1263  /* Clear out the data with this player */
1264  if( dwFlags & DPSET_LOCAL )
1265  {
1266  if ( lpGData->dwLocalDataSize != 0 )
1267  {
1268  HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1269  lpGData->lpLocalData = NULL;
1270  lpGData->dwLocalDataSize = 0;
1271  }
1272  }
1273  else
1274  {
1275  if( lpGData->dwRemoteDataSize != 0 )
1276  {
1277  HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1278  lpGData->lpRemoteData = NULL;
1279  lpGData->dwRemoteDataSize = 0;
1280  }
1281  }
1282 
1283  /* Reallocate for new data */
1284  if( lpData != NULL )
1285  {
1286  if( dwFlags & DPSET_LOCAL )
1287  {
1288  lpGData->lpLocalData = lpData;
1289  lpGData->dwLocalDataSize = dwDataSize;
1290  }
1291  else
1292  {
1293  lpGData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
1294  CopyMemory( lpGData->lpRemoteData, lpData, dwDataSize );
1295  lpGData->dwRemoteDataSize = dwDataSize;
1296  }
1297  }
1298 
1299 }
1300 
1301 /* This function will just create the storage for the new player. */
1303  DWORD dwFlags, HANDLE hEvent, BOOL bAnsi )
1304 {
1305  lpPlayerData lpPData;
1306 
1307  TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1308 
1309  /* Allocate the storage for the player and associate it with list element */
1310  lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1311  if( lpPData == NULL )
1312  {
1313  return NULL;
1314  }
1315 
1316  /* Set the desired player ID */
1317  lpPData->dpid = *lpid;
1318 
1319  DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1320 
1321  lpPData->dwFlags = dwFlags;
1322 
1323  /* If we were given an event handle, duplicate it */
1324  if( hEvent != 0 )
1325  {
1326  if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1327  GetCurrentProcess(), &lpPData->hEvent,
1329  )
1330  {
1331  /* FIXME: Memory leak */
1332  ERR( "Can't duplicate player msg handle %p\n", hEvent );
1333  }
1334  }
1335 
1336  /* Initialize the SP data section */
1338 
1339  TRACE( "Created player id 0x%08x\n", *lpid );
1340 
1341  if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1343 
1344  return lpPData;
1345 }
1346 
1347 /* Delete the contents of the DPNAME struct */
1348 static void
1350 {
1353 }
1354 
1355 /* This method assumes that all links to it are already deleted */
1356 static void DP_DeletePlayer( IDirectPlayImpl *This, DPID dpid )
1357 {
1358  lpPlayerList lpPList;
1359 
1360  TRACE( "(%p)->(0x%08x)\n", This, dpid );
1361 
1362  DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1363 
1364  if( lpPList == NULL )
1365  {
1366  ERR( "DPID 0x%08x not found\n", dpid );
1367  return;
1368  }
1369 
1370  /* Verify that this is the last reference to the data */
1371  if( --(lpPList->lpPData->uRef) )
1372  {
1373  FIXME( "Why is this not the last reference to player?\n" );
1374  DebugBreak();
1375  }
1376 
1377  /* Delete player */
1378  DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1379 
1380  CloseHandle( lpPList->lpPData->hEvent );
1381  HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1382 
1383  /* Delete Player List object */
1384  HeapFree( GetProcessHeap(), 0, lpPList );
1385 }
1386 
1388 {
1389  lpPlayerList lpPlayers;
1390 
1391  TRACE( "(%p)->(0x%08x)\n", This, dpid );
1392 
1393  if(This->dp2->lpSysGroup == NULL)
1394  return NULL;
1395 
1396  DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1397 
1398  return lpPlayers;
1399 }
1400 
1401 /* Basic area for Dst must already be allocated */
1402 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1403 {
1404  if( lpSrc == NULL )
1405  {
1406  ZeroMemory( lpDst, sizeof( *lpDst ) );
1407  lpDst->dwSize = sizeof( *lpDst );
1408  return TRUE;
1409  }
1410 
1411  if( lpSrc->dwSize != sizeof( *lpSrc) )
1412  {
1413  return FALSE;
1414  }
1415 
1416  /* Delete any existing pointers */
1417  HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1418  HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1419 
1420  /* Copy as required */
1421  CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1422 
1423  if( bAnsi )
1424  {
1425  if( lpSrc->u1.lpszShortNameA )
1426  {
1427  lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1428  strlen(lpSrc->u1.lpszShortNameA)+1 );
1429  strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1430  }
1431  if( lpSrc->u2.lpszLongNameA )
1432  {
1433  lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1434  strlen(lpSrc->u2.lpszLongNameA)+1 );
1435  strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1436  }
1437  }
1438  else
1439  {
1440  if( lpSrc->u1.lpszShortNameA )
1441  {
1442  lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1443  (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1444  strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1445  }
1446  if( lpSrc->u2.lpszLongNameA )
1447  {
1448  lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1449  (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1450  strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1451  }
1452  }
1453 
1454  return TRUE;
1455 }
1456 
1457 static void
1459  LPVOID lpData, DWORD dwDataSize )
1460 {
1461  /* Clear out the data with this player */
1462  if( dwFlags & DPSET_LOCAL )
1463  {
1464  if ( lpPData->dwLocalDataSize != 0 )
1465  {
1466  HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1467  lpPData->lpLocalData = NULL;
1468  lpPData->dwLocalDataSize = 0;
1469  }
1470  }
1471  else
1472  {
1473  if( lpPData->dwRemoteDataSize != 0 )
1474  {
1475  HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1476  lpPData->lpRemoteData = NULL;
1477  lpPData->dwRemoteDataSize = 0;
1478  }
1479  }
1480 
1481  /* Reallocate for new data */
1482  if( lpData != NULL )
1483  {
1484 
1485  if( dwFlags & DPSET_LOCAL )
1486  {
1487  lpPData->lpLocalData = lpData;
1488  lpPData->dwLocalDataSize = dwDataSize;
1489  }
1490  else
1491  {
1492  lpPData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
1493  CopyMemory( lpPData->lpRemoteData, lpData, dwDataSize );
1494  lpPData->dwRemoteDataSize = dwDataSize;
1495  }
1496  }
1497 
1498 }
1499 
1500 /* Note: lpMsgHdr is NULL for local creation, non NULL for remote creation */
1501 static HRESULT DP_IF_CreatePlayer( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidPlayer,
1502  DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags,
1503  BOOL bAnsi )
1504 {
1505  HRESULT hr = DP_OK;
1506  lpPlayerData lpPData;
1507  lpPlayerList lpPList;
1508  DWORD dwCreateFlags = 0;
1509 
1510  TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1511  This, lpidPlayer, lpPlayerName, hEvent, lpData,
1512  dwDataSize, dwFlags, bAnsi );
1513  if( This->dp2->connectionInitialized == NO_PROVIDER )
1514  {
1515  return DPERR_UNINITIALIZED;
1516  }
1517 
1518  if( dwFlags == 0 )
1519  {
1520  dwFlags = DPPLAYER_SPECTATOR;
1521  }
1522 
1523  if( lpidPlayer == NULL )
1524  {
1525  return DPERR_INVALIDPARAMS;
1526  }
1527 
1528 
1529  /* Determine the creation flags for the player. These will be passed
1530  * to the name server if requesting a player id and to the SP when
1531  * informing it of the player creation
1532  */
1533  {
1534  if( dwFlags & DPPLAYER_SERVERPLAYER )
1535  {
1536  if( *lpidPlayer == DPID_SERVERPLAYER )
1537  {
1538  /* Server player for the host interface */
1539  dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1540  }
1541  else if( *lpidPlayer == DPID_NAME_SERVER )
1542  {
1543  /* Name server - master of everything */
1545  }
1546  else
1547  {
1548  /* Server player for a non host interface */
1549  dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1550  }
1551  }
1552 
1553  if( lpMsgHdr == NULL )
1554  dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1555  }
1556 
1557  /* Verify we know how to handle all the flags */
1558  if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1559  ( dwFlags & DPPLAYER_SPECTATOR )
1560  )
1561  )
1562  {
1563  /* Assume non fatal failure */
1564  ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1565  }
1566 
1567  /* If the name is not specified, we must provide one */
1568  if( *lpidPlayer == DPID_UNKNOWN )
1569  {
1570  /* If we are the session master, we dish out the group/player ids */
1571  if( This->dp2->bHostInterface )
1572  {
1573  *lpidPlayer = DP_NextObjectId();
1574  }
1575  else
1576  {
1577  hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1578 
1579  if( FAILED(hr) )
1580  {
1581  ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1582  return hr;
1583  }
1584  }
1585  }
1586  else
1587  {
1588  /* FIXME: Would be nice to perhaps verify that we don't already have
1589  * this player.
1590  */
1591  }
1592 
1593  /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1594  player total */
1595  lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1596  hEvent, bAnsi );
1597  /* Create the list object and link it in */
1598  lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1599  if( !lpPData || !lpPList )
1600  {
1601  HeapFree( GetProcessHeap(), 0, lpPData );
1602  HeapFree( GetProcessHeap(), 0, lpPList );
1603  return DPERR_CANTADDPLAYER;
1604  }
1605 
1606  lpPData->uRef = 1;
1607  lpPList->lpPData = lpPData;
1608 
1609  /* Add the player to the system group */
1610  DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1611 
1612  /* Update the information and send it to all players in the session */
1613  DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1614 
1615  /* Let the SP know that we've created this player */
1616  if( This->dp2->spData.lpCB->CreatePlayer )
1617  {
1619 
1620  data.idPlayer = *lpidPlayer;
1621  data.dwFlags = dwCreateFlags;
1622  data.lpSPMessageHeader = lpMsgHdr;
1623  data.lpISP = This->dp2->spData.lpISP;
1624 
1625  TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1626  *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1627 
1628  hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1629  }
1630 
1631  if( FAILED(hr) )
1632  {
1633  ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1634  return hr;
1635  }
1636 
1637  /* Now let the SP know that this player is a member of the system group */
1638  if( This->dp2->spData.lpCB->AddPlayerToGroup )
1639  {
1641 
1642  data.idPlayer = *lpidPlayer;
1643  data.idGroup = DPID_SYSTEM_GROUP;
1644  data.lpISP = This->dp2->spData.lpISP;
1645 
1646  TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1647 
1648  hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1649  }
1650 
1651  if( FAILED(hr) )
1652  {
1653  ERR( "Failed to add player to sys group with sp: %s\n",
1654  DPLAYX_HresultToString(hr) );
1655  return hr;
1656  }
1657 
1658 #if 1
1659  if( !This->dp2->bHostInterface )
1660  {
1661  /* Let the name server know about the creation of this player */
1662  /* FIXME: Is this only to be done for the creation of a server player or
1663  * is this used for regular players? If only for server players, move
1664  * this call to DP_SecureOpen(...);
1665  */
1666 #if 0
1667  TRACE( "Sending message to self to get my addr\n" );
1668  DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1669 #endif
1670 
1671  hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1672  }
1673 #else
1674  /* Inform all other peers of the creation of a new player. If there are
1675  * no peers keep this quiet.
1676  * Also, if this was a remote event, no need to rebroadcast it.
1677  */
1678  if( ( lpMsgHdr == NULL ) &&
1679  This->dp2->lpSessionDesc &&
1681  {
1684 
1686  msg.dpId = *lpidPlayer;
1687  msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1688  msg.lpData = lpData;
1689  msg.dwDataSize = dwDataSize;
1690  msg.dpnName = *lpPlayerName;
1692  msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1693 
1694  /* FIXME: Correct to just use send effectively? */
1695  /* FIXME: Should size include data w/ message or just message "header" */
1696  /* FIXME: Check return code */
1698  &msg, sizeof( msg ), 0, 0, NULL, NULL );
1699  }
1700 #endif
1701 
1702  return hr;
1703 }
1704 
1707 {
1708  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1709  return IDirectPlayX_CreatePlayer( &This->IDirectPlay4A_iface, lpidPlayer, name, event, data,
1710  size, flags );
1711 }
1712 
1713 static HRESULT WINAPI IDirectPlay2Impl_CreatePlayer( IDirectPlay2 *iface, DPID *lpidPlayer,
1715 {
1716  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1717  return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
1718  size, flags );
1719 }
1720 
1723 {
1724  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
1725  return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
1726  size, flags );
1727 }
1728 
1729 static HRESULT WINAPI IDirectPlay3Impl_CreatePlayer( IDirectPlay3 *iface, DPID *lpidPlayer,
1731 {
1732  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1733  return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
1734  size, flags );
1735 }
1736 
1738  DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1739 {
1740  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1741 
1742  if( lpidPlayer == NULL )
1743  {
1744  return DPERR_INVALIDPARAMS;
1745  }
1746 
1747  if( dwFlags & DPPLAYER_SERVERPLAYER )
1748  {
1749  *lpidPlayer = DPID_SERVERPLAYER;
1750  }
1751  else
1752  {
1753  *lpidPlayer = DPID_UNKNOWN;
1754  }
1755 
1756  return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1757  lpData, dwDataSize, dwFlags, TRUE );
1758 }
1759 
1760 static HRESULT WINAPI IDirectPlay4Impl_CreatePlayer( IDirectPlay4 *iface, DPID *lpidPlayer,
1761  DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1762 {
1763  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1764 
1765  if( lpidPlayer == NULL )
1766  {
1767  return DPERR_INVALIDPARAMS;
1768  }
1769 
1770  if( dwFlags & DPPLAYER_SERVERPLAYER )
1771  {
1772  *lpidPlayer = DPID_SERVERPLAYER;
1773  }
1774  else
1775  {
1776  *lpidPlayer = DPID_UNKNOWN;
1777  }
1778 
1779  return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1780  lpData, dwDataSize, dwFlags, FALSE );
1781 }
1782 
1784 {
1785  FIXME( ":stub\n" );
1786 
1787  /* Hack solution */
1788  return DP_NextObjectId();
1789 }
1790 
1792  DPID player )
1793 {
1794  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1795  return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4A_iface, group, player );
1796 }
1797 
1799  DPID player )
1800 {
1801  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1802  return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1803 }
1804 
1806  DPID player )
1807 {
1808  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
1809  return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1810 }
1811 
1813  DPID player )
1814 {
1815  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1816  return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1817 }
1818 
1820  DPID player )
1821 {
1822  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1823  return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1824 }
1825 
1827  DPID player )
1828 {
1829  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1830  HRESULT hr = DP_OK;
1831 
1832  lpGroupData gdata;
1834 
1835  TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
1836 
1837  /* Find the group */
1838  if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
1839  return DPERR_INVALIDGROUP;
1840 
1841  /* Find the player */
1842  if ( DP_FindPlayer( This, player ) == NULL )
1843  return DPERR_INVALIDPLAYER;
1844 
1845  /* Remove the player shortcut from the group */
1846  DPQ_REMOVE_ENTRY( gdata->players, players, lpPData->dpid, ==, player, plist );
1847 
1848  if ( !plist )
1849  return DPERR_INVALIDPLAYER;
1850 
1851  /* One less reference */
1852  plist->lpPData->uRef--;
1853 
1854  /* Delete the Player List element */
1855  HeapFree( GetProcessHeap(), 0, plist );
1856 
1857  /* Inform the SP if they care */
1858  if ( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1859  {
1861 
1862  TRACE( "Calling SP RemovePlayerFromGroup\n" );
1863  data.idPlayer = player;
1864  data.idGroup = group;
1865  data.lpISP = This->dp2->spData.lpISP;
1866  hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1867  }
1868 
1869  /* Need to send a DELETEPLAYERFROMGROUP message */
1870  FIXME( "Need to send a message\n" );
1871 
1872  return hr;
1873 }
1874 
1875 typedef struct _DPRGOPContext
1876 {
1881 
1882 static BOOL CALLBACK
1884  DPID dpId,
1885  DWORD dwPlayerType,
1886  LPCDPNAME lpName,
1887  DWORD dwFlags,
1888  LPVOID lpContext )
1889 {
1890  lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1891 
1892  TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1893  dpId, dwPlayerType, lpCtxt->idGroup );
1894 
1895  if( dwPlayerType == DPPLAYERTYPE_GROUP )
1896  {
1898  lpCtxt->idGroup, dpId ) ) )
1899  ERR( "Unable to delete group 0x%08x from group 0x%08x\n", dpId, lpCtxt->idGroup );
1900  }
1902  lpCtxt->idGroup, dpId ) ) )
1903  ERR( "Unable to delete player 0x%08x from grp 0x%08x\n", dpId, lpCtxt->idGroup );
1904 
1905  return TRUE; /* Continue enumeration */
1906 }
1907 
1908 static HRESULT DP_IF_DestroyGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID idGroup, BOOL bAnsi )
1909 {
1910  lpGroupData lpGData;
1912 
1913  FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1914  This, lpMsgHdr, idGroup, bAnsi );
1915 
1916  /* Find the group */
1917  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1918  {
1919  return DPERR_INVALIDPLAYER; /* yes player */
1920  }
1921 
1922  context.This = This;
1923  context.bAnsi = bAnsi;
1924  context.idGroup = idGroup;
1925 
1926  /* Remove all players that this group has */
1928  &context, 0 );
1929 
1930  /* Remove all links to groups that this group has since this is dp3 */
1932  (void*)&context, 0 );
1933 
1934  /* Remove this group from the parent group - if it has one */
1935  if( ( idGroup != DPID_SYSTEM_GROUP ) && ( lpGData->parent != DPID_SYSTEM_GROUP ) )
1936  IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, lpGData->parent, idGroup );
1937 
1938  /* Now delete this group data and list from the system group */
1939  DP_DeleteGroup( This, idGroup );
1940 
1941  /* Let the SP know that we've destroyed this group */
1942  if( This->dp2->spData.lpCB->DeleteGroup )
1943  {
1945 
1946  FIXME( "data.dwFlags is incorrect\n" );
1947 
1948  data.idGroup = idGroup;
1949  data.dwFlags = 0;
1950  data.lpISP = This->dp2->spData.lpISP;
1951 
1952  (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1953  }
1954 
1955  FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1956 
1957  return DP_OK;
1958 }
1959 
1961 {
1962  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1963  return IDirectPlayX_DestroyGroup( &This->IDirectPlay4A_iface, group );
1964 }
1965 
1967 {
1968  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1969  return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
1970 }
1971 
1973 {
1974  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
1975  return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
1976 }
1977 
1979 {
1980  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1981  return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
1982 }
1983 
1985 {
1986  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1987  return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1988 }
1989 
1990 static HRESULT WINAPI IDirectPlay4Impl_DestroyGroup( IDirectPlay4 *iface, DPID idGroup )
1991 {
1992  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1993  return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1994 }
1995 
1996 typedef struct _DPFAGContext
1997 {
2002 
2003 static HRESULT DP_IF_DestroyPlayer( IDirectPlayImpl *This, void *lpMsgHdr, DPID idPlayer,
2004  BOOL bAnsi )
2005 {
2006  DPFAGContext cbContext;
2007 
2008  FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
2009  This, lpMsgHdr, idPlayer, bAnsi );
2010 
2011  if( This->dp2->connectionInitialized == NO_PROVIDER )
2012  {
2013  return DPERR_UNINITIALIZED;
2014  }
2015 
2016  if( DP_FindPlayer( This, idPlayer ) == NULL )
2017  {
2018  return DPERR_INVALIDPLAYER;
2019  }
2020 
2021  /* FIXME: If the player is remote, we must be the host to delete this */
2022 
2023  cbContext.This = This;
2024  cbContext.idPlayer = idPlayer;
2025  cbContext.bAnsi = bAnsi;
2026 
2027  /* Find each group and call DeletePlayerFromGroup if the player is a
2028  member of the group */
2030  DPENUMGROUPS_ALL );
2031 
2032  /* Now delete player and player list from the sys group */
2033  DP_DeletePlayer( This, idPlayer );
2034 
2035  /* Let the SP know that we've destroyed this group */
2036  if( This->dp2->spData.lpCB->DeletePlayer )
2037  {
2039 
2040  FIXME( "data.dwFlags is incorrect\n" );
2041 
2042  data.idPlayer = idPlayer;
2043  data.dwFlags = 0;
2044  data.lpISP = This->dp2->spData.lpISP;
2045 
2046  (*This->dp2->spData.lpCB->DeletePlayer)( &data );
2047  }
2048 
2049  FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
2050 
2051  return DP_OK;
2052 }
2053 
2054 static BOOL CALLBACK
2056  DPID dpId,
2057  DWORD dwPlayerType,
2058  LPCDPNAME lpName,
2059  DWORD dwFlags,
2060  LPVOID lpContext )
2061 {
2062  lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
2063 
2064  if( dwPlayerType == DPPLAYERTYPE_GROUP )
2065  {
2067 
2068  /* Enumerate all groups in this group since this will normally only
2069  * be called for top level groups
2070  */
2073 
2074  }
2075  else
2076  {
2077  ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
2078  }
2079 
2080  return TRUE;
2081 }
2082 
2084 {
2085  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2086  return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4A_iface, player );
2087 }
2088 
2089 static HRESULT WINAPI IDirectPlay2Impl_DestroyPlayer( IDirectPlay2 *iface, DPID player )
2090 {
2091  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2092  return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
2093 }
2094 
2096 {
2097  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2098  return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
2099 }
2100 
2101 static HRESULT WINAPI IDirectPlay3Impl_DestroyPlayer( IDirectPlay3 *iface, DPID player )
2102 {
2103  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2104  return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
2105 }
2106 
2108 {
2109  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2110  return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
2111 }
2112 
2113 static HRESULT WINAPI IDirectPlay4Impl_DestroyPlayer( IDirectPlay4 *iface, DPID idPlayer )
2114 {
2115  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2116  return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
2117 }
2118 
2120  GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2121 {
2122  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2123  return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4A_iface, group, instance,
2124  enumplayercb, context, flags );
2125 }
2126 
2128  GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2129 {
2130  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2131  return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
2132  enumplayercb, context, flags );
2133 }
2134 
2136  GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2137 {
2138  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2139  return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
2140  enumplayercb, context, flags );
2141 }
2142 
2144  GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2145 {
2146  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2147  return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
2148  enumplayercb, context, flags );
2149 }
2150 
2152  GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2153 {
2154  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2155  return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance, enumplayercb,
2156  context, flags );
2157 }
2158 
2160  GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2161 {
2162  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2163  lpGroupData gdata;
2165 
2166  FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
2167  context, flags );
2168 
2169  if ( This->dp2->connectionInitialized == NO_PROVIDER )
2170  return DPERR_UNINITIALIZED;
2171 
2172  /* Find the group */
2173  if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
2174  return DPERR_INVALIDGROUP;
2175 
2176  if ( DPQ_IS_EMPTY( gdata->players ) )
2177  return DP_OK;
2178 
2179  /* Walk the players in this group */
2180  for( plist = DPQ_FIRST( gdata->players ); ; plist = DPQ_NEXT( plist->players ) )
2181  {
2182  /* We do not enum the name server or app server as they are of no
2183  * consequence to the end user.
2184  */
2185  if ( ( plist->lpPData->dpid != DPID_NAME_SERVER ) &&
2186  ( plist->lpPData->dpid != DPID_SERVERPLAYER ) )
2187  {
2188  /* FIXME: Need to add stuff for flags checking */
2189  if ( !enumplayercb( plist->lpPData->dpid, DPPLAYERTYPE_PLAYER,
2190  &plist->lpPData->name, plist->lpPData->dwFlags, context ) )
2191  /* User requested break */
2192  return DP_OK;
2193  }
2194 
2195  if ( DPQ_IS_ENDOFLIST( plist->players ) )
2196  break;
2197  }
2198  return DP_OK;
2199 }
2200 
2201 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2203  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2204 {
2205  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2206  return IDirectPlayX_EnumGroups( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
2207  flags );
2208 }
2209 
2211  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2212 {
2213  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2214  return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2215  flags );
2216 }
2217 
2219  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2220 {
2221  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2222  return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2223  flags );
2224 }
2225 
2227  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2228 {
2229  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2230  return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2231  flags );
2232 }
2233 
2235  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2236 {
2237  return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
2238  context, flags );
2239 }
2240 
2241 static HRESULT WINAPI IDirectPlay4Impl_EnumGroups ( IDirectPlay4 *iface, GUID *instance,
2242  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2243 {
2244  return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
2245  context, flags );
2246 }
2247 
2249  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2250 {
2251  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2252  return IDirectPlayX_EnumPlayers( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
2253  flags );
2254 }
2255 
2257  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2258 {
2259  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2260  return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2261  flags );
2262 }
2263 
2265  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2266 {
2267  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2268  return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2269  flags );
2270 }
2271 
2273  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2274 {
2275  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2276  return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2277  flags );
2278 }
2279 
2281  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2282 {
2283  return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
2284  context, flags );
2285 }
2286 
2288  LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2289 {
2290  return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
2291  context, flags );
2292 }
2293 
2294 /* This function should call the registered callback function that the user
2295  passed into EnumSessions for each entry available.
2296  */
2298  ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2299  LPVOID lpNSInfo,
2300  DWORD dwTimeout,
2301  LPVOID lpContext )
2302 {
2303  LPDPSESSIONDESC2 lpSessionDesc;
2304 
2305  FIXME( ": not checking for conditions\n" );
2306 
2307  /* Not sure if this should be pruning but it's convenient */
2308  NS_PruneSessionCache( lpNSInfo );
2309 
2310  NS_ResetSessionEnumeration( lpNSInfo );
2311 
2312  /* Enumerate all sessions */
2313  /* FIXME: Need to indicate ANSI */
2314  while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2315  {
2316  TRACE( "EnumSessionsCallback2 invoked\n" );
2317  if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2318  {
2319  return;
2320  }
2321  }
2322 
2323  /* Invoke one last time to indicate that there is no more to come */
2324  lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2325 }
2326 
2328 {
2329  EnumSessionAsyncCallbackData* data = lpContext;
2330  HANDLE hSuicideRequest = data->hSuicideRequest;
2331  DWORD dwTimeout = data->dwTimeout;
2332 
2333  TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2334 
2335  for( ;; )
2336  {
2337  HRESULT hr;
2338 
2339  /* Sleep up to dwTimeout waiting for request to terminate thread */
2340  if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2341  {
2342  TRACE( "Thread terminating on terminate request\n" );
2343  break;
2344  }
2345 
2346  /* Now resend the enum request */
2348  data->dwEnumSessionFlags,
2349  data->lpSpData );
2350 
2351  if( FAILED(hr) )
2352  {
2353  ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2354  /* FIXME: Should we kill this thread? How to inform the main thread? */
2355  }
2356 
2357  }
2358 
2359  TRACE( "Thread terminating\n" );
2360 
2361  /* Clean up the thread data */
2362  CloseHandle( hSuicideRequest );
2363  HeapFree( GetProcessHeap(), 0, lpContext );
2364 
2365  /* FIXME: Need to have some notification to main app thread that this is
2366  * dead. It would serve two purposes. 1) allow sync on termination
2367  * so that we don't actually send something to ourselves when we
2368  * become name server (race condition) and 2) so that if we die
2369  * abnormally something else will be able to tell.
2370  */
2371 
2372  return 1;
2373 }
2374 
2376 {
2377  /* Does a thread exist? If so we were doing an async enum session */
2379  {
2380  TRACE( "Killing EnumSession thread %p\n",
2381  This->dp2->hEnumSessionThread );
2382 
2383  /* Request that the thread kill itself nicely */
2386 
2387  /* We no longer need to know about the thread */
2389 
2391  }
2392 }
2393 
2395  DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2396 {
2397  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2398  return IDirectPlayX_EnumSessions( &This->IDirectPlay4A_iface, sdesc, timeout, enumsessioncb,
2399  context, flags );
2400 }
2401 
2402 static HRESULT WINAPI IDirectPlay2Impl_EnumSessions( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
2403  DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2404 {
2405  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2406  return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
2407  context, flags );
2408 }
2409 
2411  DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2412 {
2413  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2414  return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
2415  context, flags );
2416 }
2417 
2418 static HRESULT WINAPI IDirectPlay3Impl_EnumSessions( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
2419  DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2420 {
2421  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2422  return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
2423  context, flags );
2424 }
2425 
2427  DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2428 {
2429  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2430  return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
2431  context, flags );
2432 }
2433 
2434 static HRESULT WINAPI IDirectPlay4Impl_EnumSessions( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
2435  DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2436 {
2437  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2438  void *connection;
2439  DWORD size;
2440  HRESULT hr = DP_OK;
2441 
2442  TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x)\n", This, sdesc, timeout, enumsessioncb,
2443  context, flags );
2444 
2445  if ( This->dp2->connectionInitialized == NO_PROVIDER )
2446  return DPERR_UNINITIALIZED;
2447 
2448  /* Can't enumerate if the interface is already open */
2449  if ( This->dp2->bConnectionOpen )
2450  return DPERR_GENERIC;
2451 
2452  /* The loading of a lobby provider _seems_ to require a backdoor loading
2453  * of the service provider to also associate with this DP object. This is
2454  * because the app doesn't seem to have to call EnumConnections and
2455  * InitializeConnection for the SP before calling this method. As such
2456  * we'll do their dirty work for them with a quick hack so as to always
2457  * load the TCP/IP service provider.
2458  *
2459  * The correct solution would seem to involve creating a dialog box which
2460  * contains the possible SPs. These dialog boxes most likely follow SDK
2461  * examples.
2462  */
2463  if ( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2464  {
2465  WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2466 
2467  if ( !DP_BuildSPCompoundAddr( (GUID*)&DPSPGUID_TCPIP, &connection, &size ) )
2468  {
2469  ERR( "Can't build compound addr\n" );
2470  return DPERR_GENERIC;
2471  }
2472 
2473  hr = IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, 0 );
2474  if ( FAILED(hr) )
2475  return hr;
2476 
2477  HeapFree( GetProcessHeap(), 0, connection );
2478  This->dp2->bSPInitialized = TRUE;
2479  }
2480 
2481 
2482  /* Use the service provider default? */
2483  if ( !timeout )
2484  {
2485  DPCAPS caps;
2486  caps.dwSize = sizeof( caps );
2487 
2488  IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, &caps, 0 );
2489  timeout = caps.dwTimeout;
2490  if ( !timeout )
2491  timeout = DPMSG_WAIT_5_SECS; /* Provide the TCP/IP default */
2492  }
2493 
2494  if ( flags & DPENUMSESSIONS_STOPASYNC )
2495  {
2496  DP_KillEnumSessionThread( This );
2497  return hr;
2498  }
2499 
2500  if ( flags & DPENUMSESSIONS_ASYNC )
2501  {
2502  /* Enumerate everything presently in the local session cache */
2503  DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
2504  context );
2505 
2506  if ( This->dp2->dwEnumSessionLock )
2507  return DPERR_CONNECTING;
2508 
2509  /* See if we've already created a thread to service this interface */
2511  {
2512  DWORD tid;
2513  This->dp2->dwEnumSessionLock++;
2514 
2515  /* Send the first enum request inline since the user may cancel a dialog
2516  * if one is presented. Also, may also have a connecting return code.
2517  */
2518  hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags,
2519  &This->dp2->spData );
2520 
2521  if ( SUCCEEDED(hr) )
2522  {
2524  HEAP_ZERO_MEMORY, sizeof( *data ) );
2525  /* FIXME: need to kill the thread on object deletion */
2526  data->lpSpData = &This->dp2->spData;
2527  data->requestGuid = sdesc->guidApplication;
2528  data->dwEnumSessionFlags = flags;
2529  data->dwTimeout = timeout;
2530 
2533  GetCurrentProcess(), &data->hSuicideRequest, 0, FALSE,
2535  ERR( "Can't duplicate thread killing handle\n" );
2536 
2537  TRACE( ": creating EnumSessionsRequest thread\n" );
2538  This->dp2->hEnumSessionThread = CreateThread( NULL, 0,
2539  DP_EnumSessionsSendAsyncRequestThread, data, 0, &tid );
2540  }
2541  This->dp2->dwEnumSessionLock--;
2542  }
2543  }
2544  else
2545  {
2546  /* Invalidate the session cache for the interface */
2548  /* Send the broadcast for session enumeration */
2549  hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags, &This->dp2->spData );
2550  SleepEx( timeout, FALSE );
2551  DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
2552  context );
2553  }
2554 
2555  return hr;
2556 }
2557 
2559 {
2560  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2561  return IDirectPlayX_GetCaps( &This->IDirectPlay4A_iface, caps, flags );
2562 }
2563 
2564 static HRESULT WINAPI IDirectPlay2Impl_GetCaps( IDirectPlay2 *iface, DPCAPS *caps, DWORD flags )
2565 {
2566  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2567  return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
2568 }
2569 
2571 {
2572  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2573  return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
2574 }
2575 
2576 static HRESULT WINAPI IDirectPlay3Impl_GetCaps( IDirectPlay3 *iface, DPCAPS *caps, DWORD flags )
2577 {
2578  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2579  return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
2580 }
2581 
2583 {
2584  return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
2585 }
2586 
2587 static HRESULT WINAPI IDirectPlay4Impl_GetCaps( IDirectPlay4 *iface, DPCAPS *caps, DWORD flags )
2588 {
2589  return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
2590 }
2591 
2593  DWORD *size, DWORD flags )
2594 {
2595  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2596  return IDirectPlayX_GetGroupData( &This->IDirectPlay4A_iface, group, data, size, flags );
2597 }
2598 
2599 static HRESULT WINAPI IDirectPlay2Impl_GetGroupData( IDirectPlay2 *iface, DPID group, void *data,
2600  DWORD *size, DWORD flags )
2601 {
2602  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2603  return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2604 }
2605 
2607  DWORD *size, DWORD flags )
2608 {
2609  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2610  return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2611 }
2612 
2613 static HRESULT WINAPI IDirectPlay3Impl_GetGroupData( IDirectPlay3 *iface, DPID group, void *data,
2614  DWORD *size, DWORD flags )
2615 {
2616  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2617  return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2618 }
2619 
2621  void *data, DWORD *size, DWORD flags )
2622 {
2623  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2624  return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2625 }
2626 
2628  void *data, DWORD *size, DWORD flags )
2629 {
2630  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2631  lpGroupData gdata;
2632  DWORD bufsize;
2633  void *src;
2634 
2635  TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, group, data, size, flags );
2636 
2637  if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
2638  return DPERR_INVALIDGROUP;
2639 
2640  /* How much buffer is required? */
2641  if ( flags & DPSET_LOCAL )
2642  {
2643  bufsize = gdata->dwLocalDataSize;
2644  src = gdata->lpLocalData;
2645  }
2646  else
2647  {
2648  bufsize = gdata->dwRemoteDataSize;
2649  src = gdata->lpRemoteData;
2650  }
2651 
2652  /* Is the user requesting to know how big a buffer is required? */
2653  if ( !data || *size < bufsize )
2654  {
2655  *size = bufsize;
2656  return DPERR_BUFFERTOOSMALL;
2657  }
2658 
2659  CopyMemory( data, src, bufsize );
2660 
2661  return DP_OK;
2662 }
2663 
2664 static HRESULT DP_IF_GetGroupName( IDirectPlayImpl *This, DPID idGroup, void *lpData,
2665  DWORD *lpdwDataSize, BOOL bAnsi )
2666 {
2667  lpGroupData lpGData;
2668  LPDPNAME lpName = lpData;
2669  DWORD dwRequiredDataSize;
2670 
2671  FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2672  This, idGroup, lpData, lpdwDataSize, bAnsi );
2673 
2674  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2675  {
2676  return DPERR_INVALIDGROUP;
2677  }
2678 
2679  dwRequiredDataSize = lpGData->name.dwSize;
2680 
2681  if( lpGData->name.u1.lpszShortNameA )
2682  {
2683  dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2684  }
2685 
2686  if( lpGData->name.u2.lpszLongNameA )
2687  {
2688  dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2689  }
2690 
2691  if( ( lpData == NULL ) ||
2692  ( *lpdwDataSize < dwRequiredDataSize )
2693  )
2694  {
2695  *lpdwDataSize = dwRequiredDataSize;
2696  return DPERR_BUFFERTOOSMALL;
2697  }
2698 
2699  /* Copy the structure */
2700  CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2701 
2702  if( lpGData->name.u1.lpszShortNameA )
2703  {
2704  strcpy( ((char*)lpName)+lpGData->name.dwSize,
2705  lpGData->name.u1.lpszShortNameA );
2706  }
2707  else
2708  {
2709  lpName->u1.lpszShortNameA = NULL;
2710  }
2711 
2712  if( lpGData->name.u1.lpszShortNameA )
2713  {
2714  strcpy( ((char*)lpName)+lpGData->name.dwSize,
2715  lpGData->name.u2.lpszLongNameA );
2716  }
2717  else
2718  {
2719  lpName->u2.lpszLongNameA = NULL;
2720  }
2721 
2722  return DP_OK;
2723 }
2724 
2726  DWORD *size )
2727 {
2728  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2729  return IDirectPlayX_GetGroupName( &This->IDirectPlay4A_iface, group, data, size );
2730 }
2731 
2732 static HRESULT WINAPI IDirectPlay2Impl_GetGroupName( IDirectPlay2 *iface, DPID group, void *data,
2733  DWORD *size )
2734 {
2735  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2736  return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
2737 }
2738 
2740  DWORD *size )
2741 {
2742  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2743  return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
2744 }
2745 
2746 static HRESULT WINAPI IDirectPlay3Impl_GetGroupName( IDirectPlay3 *iface, DPID group, void *data,
2747  DWORD *size )
2748 {
2749  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2750  return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
2751 }
2752 
2754  void *lpData, DWORD *lpdwDataSize )
2755 {
2756  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2757  return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2758 }
2759 
2760 static HRESULT WINAPI IDirectPlay4Impl_GetGroupName( IDirectPlay4 *iface, DPID idGroup,
2761  void *lpData, DWORD *lpdwDataSize )
2762 {
2763  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2764  return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2765 }
2766 
2768  DWORD *count )
2769 {
2770  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2771  return IDirectPlayX_GetMessageCount( &This->IDirectPlay4A_iface, player, count );
2772 }
2773 
2774 static HRESULT WINAPI IDirectPlay2Impl_GetMessageCount( IDirectPlay2 *iface, DPID player,
2775  DWORD *count )
2776 {
2777  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2778  return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
2779 }
2780 
2782  DWORD *count )
2783 {
2784  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2785  return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
2786 }
2787 
2788 static HRESULT WINAPI IDirectPlay3Impl_GetMessageCount( IDirectPlay3 *iface, DPID player,
2789  DWORD *count )
2790 {
2791  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2792  return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
2793 }
2794 
2796  DWORD *count )
2797 {
2798  return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2799 }
2800 
2801 static HRESULT WINAPI IDirectPlay4Impl_GetMessageCount( IDirectPlay4 *iface, DPID player,
2802  DWORD *count )
2803 {
2804  return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2805 }
2806 
2808  void *data, DWORD *size )
2809 {
2810  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2811  return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4A_iface, player, data, size );
2812 }
2813 
2814 static HRESULT WINAPI IDirectPlay2Impl_GetPlayerAddress( IDirectPlay2 *iface, DPID player,
2815  void *data, DWORD *size )
2816 {
2817  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2818  return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
2819 }
2820 
2822  void *data, DWORD *size )
2823 {
2824  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2825  return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
2826 }
2827 
2828 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerAddress( IDirectPlay3 *iface, DPID player,
2829  void *data, DWORD *size )
2830 {
2831  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2832  return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
2833 }
2834 
2836  void *data, DWORD *size )
2837 {
2838  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2839  FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2840  return DP_OK;
2841 }
2842 
2843 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAddress( IDirectPlay4 *iface, DPID player,
2844  void *data, DWORD *size )
2845 {
2846  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2847  FIXME( "(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2848  return DP_OK;
2849 }
2850 
2852  DPCAPS *caps, DWORD flags )
2853 {
2854  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2855  return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4A_iface, player, caps, flags );
2856 }
2857 
2858 static HRESULT WINAPI IDirectPlay2Impl_GetPlayerCaps( IDirectPlay2 *iface, DPID player,
2859  DPCAPS *caps, DWORD flags )
2860 {
2861  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2862  return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2863 }
2864 
2866  DPCAPS *caps, DWORD flags )
2867 {
2868  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2869  return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2870 }
2871 
2872 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerCaps( IDirectPlay3 *iface, DPID player,
2873  DPCAPS *caps, DWORD flags )
2874 {
2875  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2876  return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2877 }
2878 
2880  DPCAPS *caps, DWORD flags )
2881 {
2882  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2883  return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2884 }
2885 
2886 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerCaps( IDirectPlay4 *iface, DPID player,
2887  DPCAPS *caps, DWORD flags )
2888 {
2889  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2891 
2892  TRACE( "(%p)->(0x%08x,%p,0x%08x)\n", This, player, caps, flags);
2893 
2894  if ( !caps )
2895  return DPERR_INVALIDPARAMS;
2896 
2897  if ( This->dp2->connectionInitialized == NO_PROVIDER )
2898  return DPERR_UNINITIALIZED;
2899 
2900  if( caps->dwSize != sizeof(DPCAPS) )
2901  return DPERR_INVALIDPARAMS;
2902 
2903  /* Query the service provider */
2904  data.idPlayer = player;
2905  data.dwFlags = flags;
2906  data.lpCaps = caps;
2907  data.lpISP = This->dp2->spData.lpISP;
2908 
2909  return (*This->dp2->spData.lpCB->GetCaps)( &data );
2910 }
2911 
2913  void *data, DWORD *size, DWORD flags )
2914 {
2915  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2916  return IDirectPlayX_GetPlayerData( &This->IDirectPlay4A_iface, player, data, size, flags );
2917 }
2918 
2919 static HRESULT WINAPI IDirectPlay2Impl_GetPlayerData( IDirectPlay2 *iface, DPID player,
2920  void *data, DWORD *size, DWORD flags )
2921 {
2922  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2923  return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2924 }
2925 
2927  void *data, DWORD *size, DWORD flags )
2928 {
2929  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2930  return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2931 }
2932 
2933 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerData( IDirectPlay3 *iface, DPID player,
2934  void *data, DWORD *size, DWORD flags )
2935 {
2936  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2937  return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2938 }
2939 
2941  void *data, DWORD *size, DWORD flags )
2942 {
2943  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2944  return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2945 }
2946 
2947 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerData( IDirectPlay4 *iface, DPID player,
2948  void *data, DWORD *size, DWORD flags )
2949 {
2950  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2952  DWORD bufsize;
2953  void *src;
2954 
2955  TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, player, data, size, flags );
2956 
2957  if ( This->dp2->connectionInitialized == NO_PROVIDER )
2958  return DPERR_UNINITIALIZED;
2959 
2960  if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
2961  return DPERR_INVALIDPLAYER;
2962 
2963  if ( flags & DPSET_LOCAL )
2964  {
2965  bufsize = plist->lpPData->dwLocalDataSize;
2966  src = plist->lpPData->lpLocalData;
2967  }
2968  else
2969  {
2970  bufsize = plist->lpPData->dwRemoteDataSize;
2971  src = plist->lpPData->lpRemoteData;
2972  }
2973 
2974  /* Is the user requesting to know how big a buffer is required? */
2975  if ( !data || *size < bufsize )
2976  {
2977  *size = bufsize;
2978  return DPERR_BUFFERTOOSMALL;
2979  }
2980 
2981  CopyMemory( data, src, bufsize );
2982 
2983  return DP_OK;
2984 }
2985 
2986 static HRESULT DP_IF_GetPlayerName( IDirectPlayImpl *This, DPID idPlayer, void *lpData,
2987  DWORD *lpdwDataSize, BOOL bAnsi )
2988 {
2989  lpPlayerList lpPList;
2990  LPDPNAME lpName = lpData;
2991  DWORD dwRequiredDataSize;
2992 
2993  FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2994  This, idPlayer, lpData, lpdwDataSize, bAnsi );
2995 
2996  if( This->dp2->connectionInitialized == NO_PROVIDER )
2997  {
2998  return DPERR_UNINITIALIZED;
2999  }
3000 
3001  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3002  {
3003  return DPERR_INVALIDPLAYER;
3004  }
3005 
3006  dwRequiredDataSize = lpPList->lpPData->name.dwSize;
3007 
3008  if( lpPList->lpPData->name.u1.lpszShortNameA )
3009  {
3010  dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
3011  }
3012 
3013  if( lpPList->lpPData->name.u2.lpszLongNameA )
3014  {
3015  dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
3016  }
3017 
3018  if( ( lpData == NULL ) ||
3019  ( *lpdwDataSize < dwRequiredDataSize )
3020  )
3021  {
3022  *lpdwDataSize = dwRequiredDataSize;
3023  return DPERR_BUFFERTOOSMALL;
3024  }
3025 
3026  /* Copy the structure */
3027  CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
3028 
3029  if( lpPList->lpPData->name.u1.lpszShortNameA )
3030  {
3031  strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
3032  lpPList->lpPData->name.u1.lpszShortNameA );
3033  }
3034  else
3035  {
3036  lpName->u1.lpszShortNameA = NULL;
3037  }
3038 
3039  if( lpPList->lpPData->name.u1.lpszShortNameA )
3040  {
3041  strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
3042  lpPList->lpPData->name.u2.lpszLongNameA );
3043  }
3044  else
3045  {
3046  lpName->u2.lpszLongNameA = NULL;
3047  }
3048 
3049  return DP_OK;
3050 }
3051 
3053  void *data, DWORD *size )
3054 {
3055  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3056  return IDirectPlayX_GetPlayerName( &This->IDirectPlay4A_iface, player, data, size );
3057 }
3058 
3059 static HRESULT WINAPI IDirectPlay2Impl_GetPlayerName( IDirectPlay2 *iface, DPID player,
3060  void *data, DWORD *size )
3061 {
3062  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3063  return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
3064 }
3065 
3067  void *data, DWORD *size )
3068 {
3069  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3070  return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
3071 }
3072 
3073 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerName( IDirectPlay3 *iface, DPID player,
3074  void *data, DWORD *size )
3075 {
3076  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3077  return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
3078 }
3079 
3081  void *lpData, DWORD *lpdwDataSize )
3082 {
3083  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3084  return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
3085 }
3086 
3087 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerName( IDirectPlay4 *iface, DPID idPlayer,
3088  void *lpData, DWORD *lpdwDataSize )
3089 {
3090  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3091  return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
3092 }
3093 
3094 static HRESULT DP_GetSessionDesc( IDirectPlayImpl *This, void *lpData, DWORD *lpdwDataSize,
3095  BOOL bAnsi )
3096 {
3097  DWORD dwRequiredSize;
3098 
3099  TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
3100 
3101  if( This->dp2->connectionInitialized == NO_PROVIDER )
3102  {
3103  return DPERR_UNINITIALIZED;
3104  }
3105 
3106  if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
3107  {
3108  return DPERR_INVALIDPARAMS;
3109  }
3110 
3111  /* FIXME: Get from This->dp2->lpSessionDesc */
3112  dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
3113 
3114  if ( ( lpData == NULL ) ||
3115  ( *lpdwDataSize < dwRequiredSize )
3116  )
3117  {
3118  *lpdwDataSize = dwRequiredSize;
3119  return DPERR_BUFFERTOOSMALL;
3120  }
3121 
3122  DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
3123 
3124  return DP_OK;
3125 }
3126 
3128  DWORD *size )
3129 {
3130  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3131  return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4A_iface, data, size );
3132 }
3133 
3134 static HRESULT WINAPI IDirectPlay2Impl_GetSessionDesc( IDirectPlay2 *iface, void *data,
3135  DWORD *size )
3136 {
3137  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3138  return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
3139 }
3140 
3142  DWORD *size )
3143 {
3144  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3145  return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
3146 }
3147 
3148 static HRESULT WINAPI IDirectPlay3Impl_GetSessionDesc( IDirectPlay3 *iface, void *data,
3149  DWORD *size )
3150 {
3151  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3152  return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
3153 }
3154 
3156  DWORD *lpdwDataSize )
3157 {
3158  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3159  return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
3160 }
3161 
3162 static HRESULT WINAPI IDirectPlay4Impl_GetSessionDesc( IDirectPlay4 *iface, void *lpData,
3163  DWORD *lpdwDataSize )
3164 {
3165  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3166  return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
3167 }
3168 
3170 {
3171  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3172  return IDirectPlayX_Initialize( &This->IDirectPlay4A_iface, guid );
3173 }
3174 
3175 static HRESULT WINAPI IDirectPlay2Impl_Initialize( IDirectPlay2 *iface, GUID *guid )
3176 {
3177  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3178  return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
3179 }
3180 
3182 {
3183  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3184  return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
3185 }
3186 
3187 static HRESULT WINAPI IDirectPlay3Impl_Initialize( IDirectPlay3 *iface, GUID *guid )
3188 {
3189  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3190  return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
3191 }
3192 
3193 /* Intended only for COM compatibility. Always returns an error. */
3195 {
3196  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3197  TRACE("(%p)->(%p): no-op\n", This, guid );
3198  return DPERR_ALREADYINITIALIZED;
3199 }
3200 
3201 static HRESULT WINAPI IDirectPlay4Impl_Initialize( IDirectPlay4 *iface, GUID *guid )
3202 {
3203  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3204  TRACE( "(%p)->(%p): no-op\n", This, guid );
3205  return DPERR_ALREADYINITIALIZED;
3206 }
3207 
3208 
3210  const DPSECURITYDESC *lpSecurity, const DPCREDENTIALS *lpCredentials, BOOL bAnsi )
3211 {
3212  HRESULT hr = DP_OK;
3213 
3214  FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
3215  This, lpsd, dwFlags, lpSecurity, lpCredentials );
3216 
3217  if( This->dp2->connectionInitialized == NO_PROVIDER )
3218  {
3219  return DPERR_UNINITIALIZED;
3220  }
3221 
3222  if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
3223  {
3224  TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
3225  return DPERR_INVALIDPARAMS;
3226  }
3227 
3228  if( This->dp2->bConnectionOpen )
3229  {
3230  TRACE( ": rejecting already open connection.\n" );
3231  return DPERR_ALREADYINITIALIZED;
3232  }
3233 
3234  /* If we're enumerating, kill the thread */
3235  DP_KillEnumSessionThread( This );
3236 
3237  if( dwFlags & DPOPEN_CREATE )
3238  {
3239  /* Rightoo - this computer is the host and the local computer needs to be
3240  the name server so that others can join this session */
3242 
3243  This->dp2->bHostInterface = TRUE;
3244 
3245  hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
3246  if( FAILED( hr ) )
3247  {
3248  ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
3249  return hr;
3250  }
3251  }
3252 
3253  /* Invoke the conditional callback for the service provider */
3254  if( This->dp2->spData.lpCB->Open )
3255  {
3257 
3258  FIXME( "Not all data fields are correct. Need new parameter\n" );
3259 
3260  data.bCreate = (dwFlags & DPOPEN_CREATE ) != 0;
3261  data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
3262  : NS_GetNSAddr( This->dp2->lpNameServerData );
3263  data.lpISP = This->dp2->spData.lpISP;
3264  data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) != 0;
3265  data.dwOpenFlags = dwFlags;
3266  data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
3267 
3268  hr = (*This->dp2->spData.lpCB->Open)(&data);
3269  if( FAILED( hr ) )
3270  {
3271  ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
3272  return hr;
3273  }
3274  }
3275 
3276  {
3277  /* Create the system group of which everything is a part of */
3278  DPID systemGroup = DPID_SYSTEM_GROUP;
3279 
3280  hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
3281  NULL, 0, 0, TRUE );
3282 
3283  }
3284 
3285  if( dwFlags & DPOPEN_JOIN )
3286  {
3287  DPID dpidServerId = DPID_UNKNOWN;
3288 
3289  /* Create the server player for this interface. This way we can receive
3290  * messages for this session.
3291  */
3292  /* FIXME: I suppose that we should be setting an event for a receive
3293  * type of thing. That way the messaging thread could know to wake
3294  * up. DPlay would then trigger the hEvent for the player the
3295  * message is directed to.
3296  */
3297  hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
3298  0,
3300 
3301  }
3302  else if( dwFlags & DPOPEN_CREATE )
3303  {
3304  DPID dpidNameServerId = DPID_NAME_SERVER;
3305 
3306  hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
3307  0, DPPLAYER_SERVERPLAYER, bAnsi );
3308  }
3309 
3310  if( FAILED(hr) )
3311  {
3312  ERR( "Couldn't create name server/system player: %s\n",
3313  DPLAYX_HresultToString(hr) );
3314  }
3315 
3316  return hr;
3317 }
3318 
3320  DWORD flags )
3321 {
3322  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3323  return IDirectPlayX_Open( &This->IDirectPlay4A_iface, sdesc, flags );
3324 }
3325 
3326 static HRESULT WINAPI IDirectPlay2Impl_Open( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
3327  DWORD flags )
3328 {
3329  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3330  return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
3331 }
3332 
3334  DWORD flags )
3335 {
3336  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3337  return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
3338 }
3339 
3340 static HRESULT WINAPI IDirectPlay3Impl_Open( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
3341  DWORD flags )
3342 {
3343  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3344  return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
3345 }
3346 
3348  DWORD flags )
3349 {
3350  return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
3351 }
3352 
3353 static HRESULT WINAPI IDirectPlay4Impl_Open( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
3354  DWORD flags )
3355 {
3356  return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
3357 }
3358 
3359 static HRESULT DP_IF_Receive( IDirectPlayImpl *This, DPID *lpidFrom, DPID *lpidTo, DWORD dwFlags,
3360  void *lpData, DWORD *lpdwDataSize, BOOL bAnsi )
3361 {
3362  LPDPMSG lpMsg = NULL;
3363 
3364  FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
3365  This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
3366 
3367  if( This->dp2->connectionInitialized == NO_PROVIDER )
3368  {
3369  return DPERR_UNINITIALIZED;
3370  }
3371 
3372  if( dwFlags == 0 )
3373  {
3374  dwFlags = DPRECEIVE_ALL;
3375  }
3376 
3377  /* If the lpData is NULL, we must be peeking the message */
3378  if( ( lpData == NULL ) &&
3379  !( dwFlags & DPRECEIVE_PEEK )
3380  )
3381  {
3382  return DPERR_INVALIDPARAMS;
3383  }
3384 
3385  if( dwFlags & DPRECEIVE_ALL )
3386  {
3387  lpMsg = This->dp2->receiveMsgs.lpQHFirst;
3388 
3389  if( !( dwFlags & DPRECEIVE_PEEK ) )
3390  {
3391  FIXME( "Remove from queue\n" );
3392  }
3393  }
3394  else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
3395  ( dwFlags & DPRECEIVE_FROMPLAYER )
3396  )
3397  {
3398  FIXME( "Find matching message 0x%08x\n", dwFlags );
3399  }
3400  else
3401  {
3402  ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
3403  }
3404 
3405  if( lpMsg == NULL )
3406  {
3407  return DPERR_NOMESSAGES;
3408  }
3409 
3410  /* Copy into the provided buffer */
3411  if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
3412 
3413  return DP_OK;
3414 }
3415 
3417  DWORD flags, void *data, DWORD *size )
3418 {
3419  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3420  return IDirectPlayX_Receive( &This->IDirectPlay4A_iface, from, to, flags, data, size );
3421 }
3422 
3423 static HRESULT WINAPI IDirectPlay2Impl_Receive( IDirectPlay2 *iface, DPID *from, DPID *to,
3424  DWORD flags, void *data, DWORD *size )
3425 {
3426  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3427  return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
3428 }
3429 
3431  DWORD flags, void *data, DWORD *size )
3432 {
3433  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3434  return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
3435 }
3436 
3437 static HRESULT WINAPI IDirectPlay3Impl_Receive( IDirectPlay3 *iface, DPID *from, DPID *to,
3438  DWORD flags, void *data, DWORD *size )
3439 {
3440  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3441  return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
3442 }
3443 
3445  DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
3446 {
3447  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3448  return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, TRUE );
3449 }
3450 
3451 static HRESULT WINAPI IDirectPlay4Impl_Receive( IDirectPlay4 *iface, DPID *lpidFrom,
3452  DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
3453 {
3454  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3455  return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, FALSE );
3456 }
3457 
3459  DWORD flags, void *data, DWORD size )
3460 {
3461  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3462  return IDirectPlayX_Send( &This->IDirectPlay4A_iface, from, to, flags, data, size );
3463 }
3464 
3465 static HRESULT WINAPI IDirectPlay2Impl_Send( IDirectPlay2 *iface, DPID from, DPID to,
3466  DWORD flags, void *data, DWORD size )
3467 {
3468  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3469  return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
3470 }
3471 
3473  DWORD flags, void *data, DWORD size )
3474 {
3475  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3476  return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
3477 }
3478 
3479 static HRESULT WINAPI IDirectPlay3Impl_Send( IDirectPlay3 *iface, DPID from, DPID to,
3480  DWORD flags, void *data, DWORD size )
3481 {
3482  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3483  return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
3484 }
3485 
3487  DWORD flags, void *data, DWORD size )
3488 {
3489  return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
3490 }
3491 
3492 static HRESULT WINAPI IDirectPlay4Impl_Send( IDirectPlay4 *iface, DPID from, DPID to,
3493  DWORD flags, void *data, DWORD size )
3494 {
3495  return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
3496 }
3497 
3499  DWORD size, DWORD flags )
3500 {
3501  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3502  return IDirectPlayX_SetGroupData( &This->IDirectPlay4A_iface, group, data, size, flags );
3503 }
3504 
3505 static HRESULT WINAPI IDirectPlay2Impl_SetGroupData( IDirectPlay2 *iface, DPID group, void *data,
3506  DWORD size, DWORD flags )
3507 {
3508  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3509  return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
3510 }
3511 
3513  DWORD size, DWORD flags )
3514 {
3515  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3516  return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
3517 }
3518 
3519 static HRESULT WINAPI IDirectPlay3Impl_SetGroupData( IDirectPlay3 *iface, DPID group, void *data,
3520  DWORD size, DWORD flags )
3521 {
3522  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3523  return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
3524 }
3525 
3527  DWORD size, DWORD flags )
3528 {
3529  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3530  return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
3531 }
3532 
3533 static HRESULT WINAPI IDirectPlay4Impl_SetGroupData( IDirectPlay4 *iface, DPID group, void *data,
3534  DWORD size, DWORD flags )
3535 {
3536  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3537  lpGroupData gdata;
3538 
3539  TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, group, data, size, flags );
3540 
3541  /* Parameter check */
3542  if ( !data && size )
3543  return DPERR_INVALIDPARAMS;
3544 
3545  /* Find the pointer to the data for this player */
3546  if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
3547  return DPERR_INVALIDOBJECT;
3548 
3549  if ( !(flags & DPSET_LOCAL) )
3550  {
3551  FIXME( "Was this group created by this interface?\n" );
3552  /* FIXME: If this is a remote update need to allow it but not
3553  * send a message.
3554  */
3555  }
3556 
3557  DP_SetGroupData( gdata, flags, data, size );
3558 
3559  /* FIXME: Only send a message if this group is local to the session otherwise
3560  * it will have been rejected above
3561  */
3562  if ( !(flags & DPSET_LOCAL) )
3563  FIXME( "Send msg?\n" );
3564 
3565  return DP_OK;
3566 }
3567 
3568 static HRESULT DP_IF_SetGroupName( IDirectPlayImpl *This, DPID idGroup, DPNAME *lpGroupName,
3569  DWORD dwFlags, BOOL bAnsi )
3570 {
3571  lpGroupData lpGData;
3572 
3573  TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3574  lpGroupName, dwFlags, bAnsi );
3575 
3576  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3577  {
3578  return DPERR_INVALIDGROUP;
3579  }
3580 
3581  DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3582 
3583  /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3584  FIXME( "Message not sent and dwFlags ignored\n" );
3585 
3586  return DP_OK;
3587 }
3588 
3590  DPNAME *name, DWORD flags )
3591 {
3592  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3593  return IDirectPlayX_SetGroupName( &This->IDirectPlay4A_iface, group, name, flags );
3594 }
3595 
3597  DPNAME *name, DWORD flags )
3598 {
3599  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3600  return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
3601 }
3602 
3604  DPNAME *name, DWORD flags )
3605 {
3606  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3607  return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
3608 }
3609 
3611  DPNAME *name, DWORD flags )
3612 {
3613  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3614  return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
3615 }
3616 
3618  DPNAME *lpGroupName, DWORD dwFlags )
3619 {
3620  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3621  return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3622 }
3623 
3624 static HRESULT WINAPI IDirectPlay4Impl_SetGroupName( IDirectPlay4 *iface, DPID idGroup,
3625  DPNAME *lpGroupName, DWORD dwFlags )
3626 {
3627  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3628  return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3629 }
3630 
3632  void *data, DWORD size, DWORD flags )
3633 {
3634  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3635  return IDirectPlayX_SetPlayerData( &This->IDirectPlay4A_iface, player, data, size, flags );
3636 }
3637 
3638 static HRESULT WINAPI IDirectPlay2Impl_SetPlayerData( IDirectPlay2 *iface, DPID player,
3639  void *data, DWORD size, DWORD flags )
3640 {
3641  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3642  return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
3643 }
3644 
3646  void *data, DWORD size, DWORD flags )
3647 {
3648  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3649  return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
3650 }
3651 
3652 static HRESULT WINAPI IDirectPlay3Impl_SetPlayerData( IDirectPlay3 *iface, DPID player,
3653  void *data, DWORD size, DWORD flags )
3654 {
3655  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3656  return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
3657 }
3658 
3660  void *data, DWORD size, DWORD flags )
3661 {
3662  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3663  return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
3664 }
3665 
3666 static HRESULT WINAPI IDirectPlay4Impl_SetPlayerData( IDirectPlay4 *iface, DPID player,
3667  void *data, DWORD size, DWORD flags )
3668 {
3669  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3671 
3672  TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, player, data, size, flags );
3673 
3674  if ( This->dp2->connectionInitialized == NO_PROVIDER )
3675  return DPERR_UNINITIALIZED;
3676 
3677  /* Parameter check */
3678  if ( !data && size )
3679  return DPERR_INVALIDPARAMS;
3680 
3681  /* Find the pointer to the data for this player */
3682  if ( (plist = DP_FindPlayer( This, player )) == NULL )
3683  return DPERR_INVALIDPLAYER;
3684 
3685  if ( !(flags & DPSET_LOCAL) )
3686  {
3687  FIXME( "Was this group created by this interface?\n" );
3688  /* FIXME: If this is a remote update need to allow it but not
3689  * send a message.
3690  */
3691  }
3692 
3693  DP_SetPlayerData( plist->lpPData, flags, data, size );
3694 
3695  if ( !(flags & DPSET_LOCAL) )
3696  FIXME( "Send msg?\n" );
3697 
3698  return DP_OK;
3699 }
3700 
3701 static HRESULT DP_IF_SetPlayerName( IDirectPlayImpl *This, DPID idPlayer, DPNAME *lpPlayerName,
3702  DWORD dwFlags, BOOL bAnsi )
3703 {
3704  lpPlayerList lpPList;
3705 
3706  TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3707  This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3708 
3709  if( This->dp2->connectionInitialized == NO_PROVIDER )
3710  {
3711  return DPERR_UNINITIALIZED;
3712  }
3713 
3714  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3715  {
3716  return DPERR_INVALIDGROUP;
3717  }
3718 
3719  DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3720 
3721  /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3722  FIXME( "Message not sent and dwFlags ignored\n" );
3723 
3724  return DP_OK;
3725 }
3726 
3728  DPNAME *name, DWORD flags )
3729 {
3730  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3731  return IDirectPlayX_SetPlayerName( &This->IDirectPlay4A_iface, player, name, flags );
3732 }
3733 
3734 static HRESULT WINAPI IDirectPlay2Impl_SetPlayerName( IDirectPlay2 *iface, DPID player,
3735  DPNAME *name, DWORD flags )
3736 {
3737  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3738  return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
3739 }
3740 
3742  DPNAME *name, DWORD flags )
3743 {
3744  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3745  return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
3746 }
3747 
3748 static HRESULT WINAPI IDirectPlay3Impl_SetPlayerName( IDirectPlay3 *iface, DPID player,
3749  DPNAME *name, DWORD flags )
3750 {
3751  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3752  return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
3753 }
3754 
3756  DPNAME *lpPlayerName, DWORD dwFlags )
3757 {
3758  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3759  return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3760 }
3761 
3762 static HRESULT WINAPI IDirectPlay4Impl_SetPlayerName( IDirectPlay4 *iface, DPID idPlayer,
3763  DPNAME *lpPlayerName, DWORD dwFlags )
3764 {
3765  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3766  return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3767 }
3768 
3769 static HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
3770  DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3771 {
3772  DWORD dwRequiredSize;
3773  LPDPSESSIONDESC2 lpTempSessDesc;
3774 
3775  TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3776  This, lpSessDesc, dwFlags, bInitial, bAnsi );
3777 
3778  if( This->dp2->connectionInitialized == NO_PROVIDER )
3779  {
3780  return DPERR_UNINITIALIZED;
3781  }
3782 
3783  if( dwFlags )
3784  {
3785  return DPERR_INVALIDPARAMS;
3786  }
3787 
3788  /* Only the host is allowed to update the session desc */
3789  if( !This->dp2->bHostInterface )
3790  {
3791  return DPERR_ACCESSDENIED;
3792  }
3793 
3794  /* FIXME: Copy into This->dp2->lpSessionDesc */
3795  dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3796  lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3797 
3798  if( lpTempSessDesc == NULL )
3799  {
3800  return DPERR_OUTOFMEMORY;
3801  }
3802 
3803  /* Free the old */
3804  HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3805 
3806  This->dp2->lpSessionDesc = lpTempSessDesc;
3807  /* Set the new */
3808  DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3809  if( bInitial )
3810  {
3811  /*Initializing session GUID*/
3813  }
3814  /* If this is an external invocation of the interface, we should be
3815  * letting everyone know that things have changed. Otherwise this is
3816  * just an initialization and it doesn't need to be propagated.
3817  */
3818  if( !bInitial )
3819  {
3820  FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3821  }
3822 
3823  return DP_OK;
3824 }
3825 
3827  DWORD flags )
3828 {
3829  IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3830  return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4A_iface, sdesc, flags );
3831 }
3832 
3833 static HRESULT WINAPI IDirectPlay2Impl_SetSessionDesc( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
3834  DWORD flags )
3835 {
3836  IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3837  return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
3838 }
3839 
3841  DWORD flags )
3842 {
3843  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3844  return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
3845 }
3846 
3847 static HRESULT WINAPI IDirectPlay3Impl_SetSessionDesc( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
3848  DWORD flags )
3849 {
3850  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3851  return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
3852 }
3853 
3855  DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
3856 {
3857  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3858  return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3859 }
3860 
3861 static HRESULT WINAPI IDirectPlay4Impl_SetSessionDesc( IDirectPlay4 *iface,
3862  DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
3863 {
3864  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3865  return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3866 }
3867 
3868 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3870 {
3871  DWORD dwSize = 0;
3872 
3873  if( lpSessDesc == NULL )
3874  {
3875  /* Hmmm..don't need any size? */
3876  ERR( "NULL lpSessDesc\n" );
3877  return dwSize;
3878  }
3879 
3880  dwSize += sizeof( *lpSessDesc );
3881 
3882  if( bAnsi )
3883  {
3884  if( lpSessDesc->u1.lpszSessionNameA )
3885  {
3886  dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3887  }
3888 
3889  if( lpSessDesc->u2.lpszPasswordA )
3890  {
3891  dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3892  }
3893  }
3894  else /* UNICODE */
3895  {
3896  if( lpSessDesc->u1.lpszSessionName )
3897  {
3898  dwSize += sizeof( WCHAR ) *
3899  ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3900  }
3901 
3902  if( lpSessDesc->u2.lpszPassword )
3903  {
3904  dwSize += sizeof( WCHAR ) *
3905  ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3906  }
3907  }
3908 
3909  return dwSize;
3910 }
3911 
3912 /* Assumes that contiguous buffers are already allocated. */
3913 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3914  LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3915 {
3916  BYTE* lpStartOfFreeSpace;
3917 
3918  if( lpSessionDest == NULL )
3919  {
3920  ERR( "NULL lpSessionDest\n" );
3921  return;
3922  }
3923 
3924  CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3925 
3926  lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3927 
3928  if( bAnsi )
3929  {
3930  if( lpSessionSrc->u1.lpszSessionNameA )
3931  {
3932  lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3933  lpSessionDest->u1.lpszSessionNameA );
3934  lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3935  lpStartOfFreeSpace +=
3936  lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3937  }
3938 
3939  if( lpSessionSrc->u2.lpszPasswordA )
3940  {
3941  lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3942  lpSessionDest->u2.lpszPasswordA );
3943  lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3944  }
3945  }
3946  else /* UNICODE */
3947  {
3948  if( lpSessionSrc->u1.lpszSessionName )
3949  {
3950  lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3951  lpSessionDest->u1.lpszSessionName );
3952  lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3953  lpStartOfFreeSpace += sizeof(WCHAR) *
3954  ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3955  }
3956 
3957  if( lpSessionSrc->u2.lpszPassword )
3958  {
3959  lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3960  lpSessionDest->u2.lpszPassword );
3961  lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3962  }
3963  }
3964 }
3965 
3967  DPID group )
3968 {
3969  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3970  return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4A_iface, parent, group );
3971 }
3972 
3974  DPID group )
3975 {
3976  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3977  return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
3978 }
3979 
3981  DPID group )
3982 {
3983  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3984  return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
3985 }
3986 
3988  DPID group )
3989 {
3990  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3991  lpGroupData gdata;
3993 
3994  TRACE( "(%p)->(0x%08x,0x%08x)\n", This, parent, group );
3995 
3996  if ( This->dp2->connectionInitialized == NO_PROVIDER )
3997  return DPERR_UNINITIALIZED;
3998 
3999  if ( !DP_FindAnyGroup(This, parent ) )
4000  return DPERR_INVALIDGROUP;
4001 
4002  if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
4003  return DPERR_INVALIDGROUP;
4004 
4005  /* Create a player list (ie "shortcut" ) */
4006  glist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *glist ) );
4007  if ( !glist )
4008  return DPERR_CANTADDPLAYER;
4009 
4010  /* Add the shortcut */
4011  gdata->uRef++;
4012  glist->lpGData = gdata;
4013 
4014  /* Add the player to the list of players for this group */
4015  DPQ_INSERT( gdata->groups, glist, groups );
4016 
4017  /* Send a ADDGROUPTOGROUP message */
4018  FIXME( "Not sending message\n" );
4019 
4020  return DP_OK;
4021 }
4022 
4023 static HRESULT DP_IF_CreateGroupInGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID idParentGroup,
4024  DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags,
4025  BOOL bAnsi )
4026 {
4027  lpGroupData lpGParentData;
4028  lpGroupList lpGList;
4029  lpGroupData lpGData;
4030 
4031  TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
4032  This, idParentGroup, lpidGroup, lpGroupName, lpData,
4033  dwDataSize, dwFlags, bAnsi );
4034 
4035  if( This->dp2->connectionInitialized == NO_PROVIDER )
4036  {
4037  return DPERR_UNINITIALIZED;
4038  }
4039 
4040  /* Verify that the specified parent is valid */
4041  if( ( lpGParentData = DP_FindAnyGroup(This, idParentGroup ) ) == NULL )
4042  return DPERR_INVALIDGROUP;
4043 
4044  lpGData = DP_CreateGroup(This, lpidGroup, lpGroupName, dwFlags, idParentGroup, bAnsi );
4045 
4046  if( lpGData == NULL )
4047  {
4048  return DPERR_CANTADDPLAYER; /* yes player not group */
4049  }
4050 
4051  /* Something else is referencing this data */
4052  lpGData->uRef++;
4053 
4054  DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
4055 
4056  /* The list has now been inserted into the interface group list. We now
4057  need to put a "shortcut" to this group in the parent group */
4058  lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
4059  if( lpGList == NULL )
4060  {
4061  FIXME( "Memory leak\n" );
4062  return DPERR_CANTADDPLAYER; /* yes player not group */
4063  }
4064 
4065  lpGList->lpGData = lpGData;
4066 
4067  DPQ_INSERT( lpGParentData->groups, lpGList, groups );
4068 
4069  /* Let the SP know that we've created this group */
4070  if( This->dp2->spData.lpCB->CreateGroup )
4071  {
4073 
4074  TRACE( "Calling SP CreateGroup\n" );
4075 
4076  data.idGroup = *lpidGroup;
4077  data.dwFlags = dwFlags;
4078  data.lpSPMessageHeader = lpMsgHdr;
4079  data.lpISP = This->dp2->spData.lpISP;
4080 
4081  (*This->dp2->spData.lpCB->CreateGroup)( &data );
4082  }
4083 
4084  /* Inform all other peers of the creation of a new group. If there are
4085  * no peers keep this quiet.
4086  */
4087  if( This->dp2->lpSessionDesc &&
4089  {
4091 
4094  msg.dpId = *lpidGroup;
4095  msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
4096  msg.lpData = lpData;
4097  msg.dwDataSize = dwDataSize;
4098  msg.dpnName = *lpGroupName;
4099 
4100  /* FIXME: Correct to just use send effectively? */
4101  /* FIXME: Should size include data w/ message or just message "header" */
4102  /* FIXME: Check return code */
4104  sizeof( msg ), 0, 0, NULL, NULL );
4105  }
4106 
4107  return DP_OK;
4108 }
4109 
4111  DPID *group, DPNAME *name, void *data, DWORD size, DWORD flags )
4112 {
4113  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4114  return IDirectPlayX_CreateGroupInGroup( &This->IDirectPlay4A_iface, parent, group, name,
4115  data, size, flags );
4116 }
4117 
4119  DPID *group, DPNAME *name, void *data, DWORD size, DWORD flags )
4120 {
4121  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4122  return IDirectPlayX_CreateGroupInGroup( &This->IDirectPlay4_iface, parent, group, name,
4123  data, size, flags );
4124 }
4125 
4127  DPID idParentGroup, DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize,
4128  DWORD dwFlags )
4129 {
4130  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4131 
4132  *lpidGroup = DPID_UNKNOWN;
4133 
4134  return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
4135  dwDataSize, dwFlags, TRUE );
4136 }
4137 
4138 static HRESULT WINAPI IDirectPlay4Impl_CreateGroupInGroup( IDirectPlay4 *iface, DPID idParentGroup,
4139  DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
4140 {
4141  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4142 
4143  *lpidGroup = DPID_UNKNOWN;
4144 
4145  return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
4146  dwDataSize, dwFlags, FALSE );
4147 }
4148 
4150  DPID group )
4151 {
4152  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4153  return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4A_iface, parent, group );
4154 }
4155 
4157  DPID group )
4158 {
4159  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4160  return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
4161 }
4162 
4164  DPID group )
4165 {
4166  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4167  return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
4168 }
4169 
4171  DPID group )
4172 {
4173  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4175  lpGroupData parentdata;
4176 
4177  TRACE("(%p)->(0x%08x,0x%08x)\n", This, parent, group );
4178 
4179  /* Is the parent group valid? */
4180  if ( ( parentdata = DP_FindAnyGroup(This, parent ) ) == NULL )
4181  return DPERR_INVALIDGROUP;
4182 
4183  /* Remove the group from the parent group queue */
4184  DPQ_REMOVE_ENTRY( parentdata->groups, groups, lpGData->dpid, ==, group, glist );
4185 
4186  if ( glist == NULL )
4187  return DPERR_INVALIDGROUP;
4188 
4189  /* Decrement the ref count */
4190  glist->lpGData->uRef--;
4191 
4192  /* Free up the list item */
4193  HeapFree( GetProcessHeap(), 0, glist );
4194 
4195  /* Should send a DELETEGROUPFROMGROUP message */
4196  FIXME( "message not sent\n" );
4197 
4198  return DP_OK;
4199 }
4200 
4201 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
4202  LPDWORD lpdwBufSize )
4203 {
4204  DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
4205  HRESULT hr;
4206 
4207  dpCompoundAddress.dwDataSize = sizeof( GUID );
4208  dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
4209  dpCompoundAddress.lpData = lpcSpGuid;
4210 
4211  *lplpAddrBuf = NULL;
4212  *lpdwBufSize = 0;
4213 
4214  hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
4215  lpdwBufSize, TRUE );
4216 
4217  if( hr != DPERR_BUFFERTOOSMALL )
4218  {
4219  ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
4220  return FALSE;
4221  }
4222 
4223  /* Now allocate the buffer */
4224  *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4225  *lpdwBufSize );
4226 
4227  hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
4228  lpdwBufSize, TRUE );
4229  if( FAILED(hr) )
4230  {
4231  ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
4232  return FALSE;
4233  }
4234 
4235  return TRUE;
4236 }
4237 
4239  const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
4240 {
4241  IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4242  return IDirectPlayX_EnumConnections( &This->IDirectPlay4A_iface, application, enumcb, context,
4243  flags );
4244 }
4245 
4247  const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
4248 {
4249  IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4250  return IDirectPlayX_EnumConnections( &This->IDirectPlay4_iface, application, enumcb, context,
4251  flags );
4252 }
4253 
4255  const GUID *lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, void *lpContext,
4256  DWORD dwFlags )
4257 {
4258  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4259  TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
4260 
4261  /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
4262  if( dwFlags == 0 )
4263  {
4264  dwFlags = DPCONNECTION_DIRECTPLAY;
4265  }
4266 
4267  if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
4268  ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
4269  )
4270  {
4271  return DPERR_INVALIDFLAGS;
4272  }
4273 
4274  if( !lpEnumCallback )
4275  {
4276  return DPERR_INVALIDPARAMS;
4277  }
4278 
4279  /* Enumerate DirectPlay service providers */
4280  if( dwFlags & DPCONNECTION_DIRECTPLAY )
4281  {
4282  HKEY hkResult;
4283  LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4284  LPCSTR guidDataSubKey = "Guid";
4285  char subKeyName[51];
4286  DWORD dwIndex, sizeOfSubKeyName=50;
4288 
4289  /* Need to loop over the service providers in the registry */
4290  if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4291  0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4292  {
4293  /* Hmmm. Does this mean that there are no service providers? */
4294  ERR(": no service providers?\n");
4295  return DP_OK;
4296  }
4297 
4298 
4299  /* Traverse all the service providers we have available */
4300  for( dwIndex=0;
4301  RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4302  NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4303  ++dwIndex, sizeOfSubKeyName=51 )
4304  {
4305 
4306  HKEY hkServiceProvider;
4307  GUID serviceProviderGUID;
4308  DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
4309  char returnBuffer[51];
4310  WCHAR buff[51];
4311  DPNAME dpName;
4312  BOOL bBuildPass;
4313 
4314  LPVOID lpAddressBuffer = NULL;
4315  DWORD dwAddressBufferSize = 0;
4316 
4317  TRACE(" this time through: %s\n", subKeyName );
4318 
4319  /* Get a handle for this particular service provider */
4320  if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4321  &hkServiceProvider ) != ERROR_SUCCESS )
4322  {
4323  ERR(": what the heck is going on?\n" );
4324  continue;
4325  }
4326 
4327  if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4328  NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
4329  &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4330  {
4331  ERR(": missing GUID registry data members\n" );
4332  RegCloseKey(hkServiceProvider);
4333  continue;
4334  }
4335  RegCloseKey(hkServiceProvider);
4336 
4337  /* FIXME: Check return types to ensure we're interpreting data right */
4338  MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4339  CLSIDFromString( buff, &serviceProviderGUID );
4340  /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4341 
4342  /* Fill in the DPNAME struct for the service provider */
4343  dpName.dwSize = sizeof( dpName );
4344  dpName.dwFlags = 0;
4345  dpName.u1.lpszShortNameA = subKeyName;
4346  dpName.u2.lpszLongNameA = NULL;
4347 
4348  /* Create the compound address for the service provider.
4349  * NOTE: This is a gruesome architectural scar right now. DP
4350  * uses DPL and DPL uses DP. Nasty stuff. This may be why the
4351  * native dll just gets around this little bit by allocating an
4352  * 80 byte buffer which isn't even filled with a valid compound
4353  * address. Oh well. Creating a proper compound address is the
4354  * way to go anyways despite this method taking slightly more
4355  * heap space and realtime :) */
4356 
4357  bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
4358