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