xref: /reactos/dll/directx/wine/dplayx/dplay.c (revision 1734f297)
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 
41 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
42 
43 /* FIXME: Should this be externed? */
44 extern HRESULT DPL_CreateCompoundAddress
45 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
46   LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
47 
48 
49 /* Local function prototypes */
50 static lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid );
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 );
55 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
56                                                   DWORD dwPlayerType,
57                                                   LPCDPNAME lpName,
58                                                   DWORD dwFlags,
59                                                   LPVOID lpContext );
60 static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid );
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 
101 static inline IDirectPlayImpl *impl_from_IDirectPlay2A( IDirectPlay2A *iface )
102 {
103     return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay2A_iface );
104 }
105 
106 static inline IDirectPlayImpl *impl_from_IDirectPlay3A( IDirectPlay3A *iface )
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 
116 static inline IDirectPlayImpl *impl_from_IDirectPlay4A( IDirectPlay4A *iface )
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 
126 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
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(),
155                                         HEAP_ZERO_MEMORY,
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 
202 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
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   {
215     DPSP_SHUTDOWNDATA data;
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 
256 static void dplay_destroy(IDirectPlayImpl *obj)
257 {
258      DP_DestroyDirectPlay2( obj );
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 {
266   return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
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 */
281     case DPMSGCMD_ENUMSESSIONSREQUEST:
282       /* Reply expected */
283       NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
284       break;
285 
286     /* Name server needs to handle this request */
287     case DPMSGCMD_ENUMSESSIONSREPLY:
288       /* No reply expected */
289       NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
290                                         This->dp2->spData.dwSPHeaderSize,
291                                         lpcMessageBody,
292                                         This->dp2->lpNameServerData );
293       break;
294 
295     case DPMSGCMD_REQUESTNEWPLAYERID:
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 
312       lpReply->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
313       lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
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 
323     case DPMSGCMD_GETNAMETABLEREPLY:
324     case DPMSGCMD_NEWPLAYERIDREPLY:
325       DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
326       break;
327 
328     case DPMSGCMD_JUSTENVELOPE:
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 
333     case DPMSGCMD_FORWARDADDPLAYER:
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 
338     case DPMSGCMD_FORWARDADDPLAYERNACK:
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 {
356     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
357     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
358 }
359 
360 static ULONG WINAPI IDirectPlayImpl_AddRef( IDirectPlay *iface )
361 {
362     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
375     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 
386 static HRESULT WINAPI IDirectPlayImpl_AddPlayerToGroup( IDirectPlay *iface, DPID group,
387         DPID player )
388 {
389     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
396     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
404     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 
410 static HRESULT WINAPI IDirectPlayImpl_CreateGroup( IDirectPlay *iface, DPID *group, LPSTR name,
411         LPSTR fullname )
412 {
413     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
414     FIXME( "(%p)->(%p,%s,%s): stub\n", This, group, debugstr_a( name ), debugstr_a( fullname ) );
415     return E_NOTIMPL;
416 }
417 
418 static HRESULT WINAPI IDirectPlayImpl_DeletePlayerFromGroup( IDirectPlay *iface, DPID group,
419         DPID player )
420 {
421     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
428     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
435     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
436     FIXME( "(%p)->(0x%08x): stub\n", This, group );
437     return E_NOTIMPL;
438 }
439 
440 static HRESULT WINAPI IDirectPlayImpl_EnableNewPlayers( IDirectPlay *iface, BOOL enable )
441 {
442     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
443     FIXME( "(%p)->(%d): stub\n", This, enable );
444     return E_NOTIMPL;
445 }
446 
447 static HRESULT WINAPI IDirectPlayImpl_EnumGroupPlayers( IDirectPlay *iface, DPID group,
448         LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
449 {
450     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
451     FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, group, enumplayercb, context, flags );
452     return E_NOTIMPL;
453 }
454 
455 static HRESULT WINAPI IDirectPlayImpl_EnumGroups( IDirectPlay *iface, DWORD session,
456         LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
457 {
458     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
459     FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, session, enumplayercb, context, flags );
460     return E_NOTIMPL;
461 }
462 
463 static HRESULT WINAPI IDirectPlayImpl_EnumPlayers( IDirectPlay *iface, DWORD session,
464         LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
465 {
466     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
474     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
482     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
490     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
497     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
505     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
513     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
520     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
528     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
529     FIXME( "(%p)->(%p,%p,0x%08x,%p,%p): stub\n", This, from, to, flags, data, size );
530     return E_NOTIMPL;
531 }
532 
533 static HRESULT WINAPI IDirectPlayImpl_SaveSession( IDirectPlay *iface, LPSTR reserved )
534 {
535     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
543     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
551     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
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 {
559     IDirectPlayImpl_QueryInterface,
560     IDirectPlayImpl_AddRef,
561     IDirectPlayImpl_Release,
562     IDirectPlayImpl_AddPlayerToGroup,
563     IDirectPlayImpl_Close,
564     IDirectPlayImpl_CreatePlayer,
565     IDirectPlayImpl_CreateGroup,
566     IDirectPlayImpl_DeletePlayerFromGroup,
567     IDirectPlayImpl_DestroyPlayer,
568     IDirectPlayImpl_DestroyGroup,
569     IDirectPlayImpl_EnableNewPlayers,
570     IDirectPlayImpl_EnumGroupPlayers,
571     IDirectPlayImpl_EnumGroups,
572     IDirectPlayImpl_EnumPlayers,
573     IDirectPlayImpl_EnumSessions,
574     IDirectPlayImpl_GetCaps,
575     IDirectPlayImpl_GetMessageCount,
576     IDirectPlayImpl_GetPlayerCaps,
577     IDirectPlayImpl_GetPlayerName,
578     IDirectPlayImpl_Initialize,
579     IDirectPlayImpl_Open,
580     IDirectPlayImpl_Receive,
581     IDirectPlayImpl_SaveSession,
582     IDirectPlayImpl_Send,
583     IDirectPlayImpl_SetPlayerName,
584 };
585 
586 
587 static HRESULT WINAPI IDirectPlay2AImpl_QueryInterface( IDirectPlay2A *iface, REFIID riid,
588         void **ppv )
589 {
590     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
591     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
592 }
593 
594 static HRESULT WINAPI IDirectPlay2Impl_QueryInterface( IDirectPlay2 *iface, REFIID riid,
595         void **ppv )
596 {
597     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
598     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
599 }
600 
601 static HRESULT WINAPI IDirectPlay3AImpl_QueryInterface( IDirectPlay3A *iface, REFIID riid,
602         void **ppv )
603 {
604     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
605     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
606 }
607 
608 static HRESULT WINAPI IDirectPlay3Impl_QueryInterface( IDirectPlay3 *iface, REFIID riid,
609         void **ppv )
610 {
611     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
612     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
613 }
614 
615 static HRESULT WINAPI IDirectPlay4AImpl_QueryInterface( IDirectPlay4A *iface, REFIID riid,
616         void **ppv )
617 {
618     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
619     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
620 }
621 
622 static HRESULT WINAPI IDirectPlay4Impl_QueryInterface( IDirectPlay4 *iface, REFIID riid,
623         void **ppv )
624 {
625     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
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 
678 static ULONG WINAPI IDirectPlay2AImpl_AddRef( IDirectPlay2A *iface )
679 {
680     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
693     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
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 
704 static ULONG WINAPI IDirectPlay3AImpl_AddRef( IDirectPlay3A *iface )
705 {
706     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
719     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
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 
730 static ULONG WINAPI IDirectPlay4AImpl_AddRef(IDirectPlay4A *iface)
731 {
732     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
745     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
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 
756 static ULONG WINAPI IDirectPlay2AImpl_Release( IDirectPlay2A *iface )
757 {
758     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
771     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
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 
782 static ULONG WINAPI IDirectPlay3AImpl_Release( IDirectPlay3A *iface )
783 {
784     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
797     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
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 
808 static ULONG WINAPI IDirectPlay4AImpl_Release(IDirectPlay4A *iface)
809 {
810     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
823     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
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 
834 static HRESULT WINAPI IDirectPlay2AImpl_AddPlayerToGroup( IDirectPlay2A *iface, DPID group,
835         DPID player )
836 {
837     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
838     return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4A_iface, group, player );
839 }
840 
841 static HRESULT WINAPI IDirectPlay2Impl_AddPlayerToGroup( IDirectPlay2 *iface, DPID group,
842         DPID player )
843 {
844     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
845     return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
846 }
847 
848 static HRESULT WINAPI IDirectPlay3AImpl_AddPlayerToGroup( IDirectPlay3A *iface, DPID group,
849         DPID player )
850 {
851     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
852     return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
853 }
854 
855 static HRESULT WINAPI IDirectPlay3Impl_AddPlayerToGroup( IDirectPlay3 *iface, DPID group,
856         DPID player )
857 {
858     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
859     return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
860 }
861 
862 static HRESULT WINAPI IDirectPlay4AImpl_AddPlayerToGroup( IDirectPlay4A *iface, DPID group,
863         DPID player )
864 {
865     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
866     return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
867 }
868 
869 static HRESULT WINAPI IDirectPlay4Impl_AddPlayerToGroup( IDirectPlay4 *iface, DPID group,
870         DPID player )
871 {
872     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
873     lpGroupData  gdata;
874     lpPlayerList plist;
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     {
905         DPSP_ADDPLAYERTOGROUPDATA data;
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     {
924         DPMSG_ADDPLAYERTOGROUP msg;
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 */
933         IDirectPlayX_SendEx( iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
934                 0, 0, NULL, NULL );
935     }
936 
937     return DP_OK;
938 }
939 
940 static HRESULT WINAPI IDirectPlay2AImpl_Close( IDirectPlay2A *iface )
941 {
942     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
943     return IDirectPlayX_Close( &This->IDirectPlay4A_iface );
944 }
945 
946 static HRESULT WINAPI IDirectPlay2Impl_Close( IDirectPlay2 *iface )
947 {
948     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
949     return IDirectPlayX_Close( &This->IDirectPlay4_iface );
950 }
951 
952 static HRESULT WINAPI IDirectPlay3AImpl_Close( IDirectPlay3A *iface )
953 {
954     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
955     return IDirectPlayX_Close( &This->IDirectPlay4_iface );
956 }
957 
958 static HRESULT WINAPI IDirectPlay3Impl_Close( IDirectPlay3 *iface )
959 {
960     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
961     return IDirectPlayX_Close( &This->IDirectPlay4_iface );
962 }
963 
964 static HRESULT WINAPI IDirectPlay4AImpl_Close( IDirectPlay4A *iface )
965 {
966     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
967     return IDirectPlayX_Close( &This->IDirectPlay4_iface);
968 }
969 
970 static HRESULT WINAPI IDirectPlay4Impl_Close( IDirectPlay4 *iface )
971 {
972     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
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     {
984         DPSP_CLOSEDATA data;
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 
999 static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, const DPNAME *lpName,
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 */
1032 static void DP_DeleteGroup( IDirectPlayImpl *This, DPID dpid )
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 
1061 static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid )
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   {
1149     DPSP_CREATEGROUPDATA data;
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   {
1179     DPMSG_CREATEPLAYERORGROUP msg;
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 
1201 static HRESULT WINAPI IDirectPlay2AImpl_CreateGroup( IDirectPlay2A *iface, DPID *lpidGroup,
1202         DPNAME *name, void *data, DWORD size, DWORD flags )
1203 {
1204     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
1212     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1213     return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, lpidGroup, name, data, size,
1214             flags );
1215 }
1216 
1217 static HRESULT WINAPI IDirectPlay3AImpl_CreateGroup( IDirectPlay3A *iface, DPID *group,
1218         DPNAME *name, void *data, DWORD size, DWORD flags )
1219 {
1220     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
1228     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1229     return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, lpidGroup, name, data, size,
1230             flags );
1231 }
1232 
1233 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroup( IDirectPlay4A *iface, DPID *lpidGroup,
1234         DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1235 {
1236     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
1247     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
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
1257 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
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.  */
1299 static lpPlayerData DP_CreatePlayer( IDirectPlayImpl *This, DPID *lpid, DPNAME *lpName,
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   {
1323     if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1324                           GetCurrentProcess(), &lpPData->hEvent,
1325                           0, FALSE, DUPLICATE_SAME_ACCESS )
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 */
1334   lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1335 
1336   TRACE( "Created player id 0x%08x\n", *lpid );
1337 
1338   if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1339     This->dp2->lpSessionDesc->dwCurrentPlayers++;
1340 
1341   return lpPData;
1342 }
1343 
1344 /* Delete the contents of the DPNAME struct */
1345 static void
1346 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1347 {
1348   HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1349   HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1350 }
1351 
1352 /* This method assumes that all links to it are already deleted */
1353 static void DP_DeletePlayer( IDirectPlayImpl *This, DPID dpid )
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 
1384 static lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid )
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
1455 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
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   {
1517     dwFlags = DPPLAYER_SPECTATOR;
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   {
1531     if( dwFlags & DPPLAYER_SERVERPLAYER )
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 */
1541         dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
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 ) ||
1556          ( dwFlags & DPPLAYER_SPECTATOR )
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   {
1615     DPSP_CREATEPLAYERDATA data;
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   {
1637     DPSP_ADDPLAYERTOGROUPDATA data;
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",
1651          DPLAYX_HresultToString(hr) );
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   {
1679     DPMSG_CREATEPLAYERORGROUP msg;
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 
1702 static HRESULT WINAPI IDirectPlay2AImpl_CreatePlayer( IDirectPlay2A *iface, DPID *lpidPlayer,
1703         DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
1704 {
1705     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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,
1711         DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
1712 {
1713     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1714     return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
1715             size, flags );
1716 }
1717 
1718 static HRESULT WINAPI IDirectPlay3AImpl_CreatePlayer( IDirectPlay3A *iface, DPID *lpidPlayer,
1719         DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
1720 {
1721     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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,
1727         DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
1728 {
1729     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1730     return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
1731             size, flags );
1732 }
1733 
1734 static HRESULT WINAPI IDirectPlay4AImpl_CreatePlayer( IDirectPlay4A *iface, DPID *lpidPlayer,
1735         DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1736 {
1737   IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1738 
1739   if( lpidPlayer == NULL )
1740   {
1741     return DPERR_INVALIDPARAMS;
1742   }
1743 
1744   if( dwFlags & DPPLAYER_SERVERPLAYER )
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 {
1760   IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1761 
1762   if( lpidPlayer == NULL )
1763   {
1764     return DPERR_INVALIDPARAMS;
1765   }
1766 
1767   if( dwFlags & DPPLAYER_SERVERPLAYER )
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 
1780 static DPID DP_GetRemoteNextObjectId(void)
1781 {
1782   FIXME( ":stub\n" );
1783 
1784   /* Hack solution */
1785   return DP_NextObjectId();
1786 }
1787 
1788 static HRESULT WINAPI IDirectPlay2AImpl_DeletePlayerFromGroup( IDirectPlay2A *iface, DPID group,
1789         DPID player )
1790 {
1791     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1792     return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4A_iface, group, player );
1793 }
1794 
1795 static HRESULT WINAPI IDirectPlay2Impl_DeletePlayerFromGroup( IDirectPlay2 *iface, DPID group,
1796         DPID player )
1797 {
1798     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1799     return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1800 }
1801 
1802 static HRESULT WINAPI IDirectPlay3AImpl_DeletePlayerFromGroup( IDirectPlay3A *iface, DPID group,
1803         DPID player )
1804 {
1805     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
1806     return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1807 }
1808 
1809 static HRESULT WINAPI IDirectPlay3Impl_DeletePlayerFromGroup( IDirectPlay3 *iface, DPID group,
1810         DPID player )
1811 {
1812     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1813     return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1814 }
1815 
1816 static HRESULT WINAPI IDirectPlay4AImpl_DeletePlayerFromGroup( IDirectPlay4A *iface, DPID group,
1817         DPID player )
1818 {
1819     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1820     return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1821 }
1822 
1823 static HRESULT WINAPI IDirectPlay4Impl_DeletePlayerFromGroup( IDirectPlay4 *iface, DPID group,
1824         DPID player )
1825 {
1826     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1827     HRESULT hr = DP_OK;
1828 
1829     lpGroupData  gdata;
1830     lpPlayerList plist;
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     {
1857         DPSP_REMOVEPLAYERFROMGROUPDATA data;
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 {
1874   IDirectPlayImpl   *This;
1875   BOOL              bAnsi;
1876   DPID              idGroup;
1877 } DPRGOPContext, *lpDPRGOPContext;
1878 
1879 static BOOL CALLBACK
1880 cbRemoveGroupOrPlayer(
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   {
1894     if ( FAILED( IDirectPlayX_DeleteGroupFromGroup( &lpCtxt->This->IDirectPlay4_iface,
1895                     lpCtxt->idGroup, dpId ) ) )
1896       ERR( "Unable to delete group 0x%08x from group 0x%08x\n", dpId, lpCtxt->idGroup );
1897   }
1898   else if ( FAILED( IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface,
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;
1908   DPRGOPContext context;
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   {
1941     DPSP_DELETEGROUPDATA data;
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 
1957 static HRESULT WINAPI IDirectPlay2AImpl_DestroyGroup( IDirectPlay2A *iface, DPID group )
1958 {
1959     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1960     return IDirectPlayX_DestroyGroup( &This->IDirectPlay4A_iface, group );
1961 }
1962 
1963 static HRESULT WINAPI IDirectPlay2Impl_DestroyGroup( IDirectPlay2 *iface, DPID group )
1964 {
1965     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1966     return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
1967 }
1968 
1969 static HRESULT WINAPI IDirectPlay3AImpl_DestroyGroup( IDirectPlay3A *iface, DPID group )
1970 {
1971     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
1972     return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
1973 }
1974 
1975 static HRESULT WINAPI IDirectPlay3Impl_DestroyGroup( IDirectPlay3 *iface, DPID group )
1976 {
1977     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1978     return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
1979 }
1980 
1981 static HRESULT WINAPI IDirectPlay4AImpl_DestroyGroup( IDirectPlay4A *iface, DPID idGroup )
1982 {
1983     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1984     return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1985 }
1986 
1987 static HRESULT WINAPI IDirectPlay4Impl_DestroyGroup( IDirectPlay4 *iface, DPID idGroup )
1988 {
1989     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1990     return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1991 }
1992 
1993 typedef struct _DPFAGContext
1994 {
1995   IDirectPlayImpl   *This;
1996   DPID              idPlayer;
1997   BOOL              bAnsi;
1998 } DPFAGContext, *lpDPFAGContext;
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   {
2035     DPSP_DELETEPLAYERDATA data;
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
2052 cbDeletePlayerFromAllGroups(
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   {
2063     IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, lpCtxt->idPlayer );
2064 
2065     /* Enumerate all groups in this group since this will normally only
2066      * be called for top level groups
2067      */
2068     IDirectPlayX_EnumGroupsInGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, NULL,
2069             cbDeletePlayerFromAllGroups, lpContext, DPENUMGROUPS_ALL);
2070 
2071   }
2072   else
2073   {
2074     ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
2075   }
2076 
2077   return TRUE;
2078 }
2079 
2080 static HRESULT WINAPI IDirectPlay2AImpl_DestroyPlayer( IDirectPlay2A *iface, DPID player )
2081 {
2082     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2083     return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4A_iface, player );
2084 }
2085 
2086 static HRESULT WINAPI IDirectPlay2Impl_DestroyPlayer( IDirectPlay2 *iface, DPID player )
2087 {
2088     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2089     return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
2090 }
2091 
2092 static HRESULT WINAPI IDirectPlay3AImpl_DestroyPlayer( IDirectPlay3A *iface, DPID player )
2093 {
2094     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2095     return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
2096 }
2097 
2098 static HRESULT WINAPI IDirectPlay3Impl_DestroyPlayer( IDirectPlay3 *iface, DPID player )
2099 {
2100     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2101     return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
2102 }
2103 
2104 static HRESULT WINAPI IDirectPlay4AImpl_DestroyPlayer( IDirectPlay4A *iface, DPID idPlayer )
2105 {
2106     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2107     return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
2108 }
2109 
2110 static HRESULT WINAPI IDirectPlay4Impl_DestroyPlayer( IDirectPlay4 *iface, DPID idPlayer )
2111 {
2112     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2113     return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
2114 }
2115 
2116 static HRESULT WINAPI IDirectPlay2AImpl_EnumGroupPlayers( IDirectPlay2A *iface, DPID group,
2117         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2118 {
2119     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2120     return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4A_iface, group, instance,
2121             enumplayercb, context, flags );
2122 }
2123 
2124 static HRESULT WINAPI IDirectPlay2Impl_EnumGroupPlayers( IDirectPlay2 *iface, DPID group,
2125         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2126 {
2127     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2128     return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
2129             enumplayercb, context, flags );
2130 }
2131 
2132 static HRESULT WINAPI IDirectPlay3AImpl_EnumGroupPlayers( IDirectPlay3A *iface, DPID group,
2133         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2134 {
2135     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2136     return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
2137             enumplayercb, context, flags );
2138 }
2139 
2140 static HRESULT WINAPI IDirectPlay3Impl_EnumGroupPlayers( IDirectPlay3 *iface, DPID group,
2141         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2142 {
2143     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2144     return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
2145             enumplayercb, context, flags );
2146 }
2147 
2148 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupPlayers( IDirectPlay4A *iface, DPID group,
2149         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2150 {
2151     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2152     return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance, enumplayercb,
2153             context, flags );
2154 }
2155 
2156 static HRESULT WINAPI IDirectPlay4Impl_EnumGroupPlayers( IDirectPlay4 *iface, DPID group,
2157         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2158 {
2159     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2160     lpGroupData  gdata;
2161     lpPlayerList plist;
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) */
2199 static HRESULT WINAPI IDirectPlay2AImpl_EnumGroups( IDirectPlay2A *iface, GUID *instance,
2200         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2201 {
2202     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2203     return IDirectPlayX_EnumGroups( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
2204             flags );
2205 }
2206 
2207 static HRESULT WINAPI IDirectPlay2Impl_EnumGroups( IDirectPlay2 *iface, GUID *instance,
2208         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2209 {
2210     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2211     return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2212             flags );
2213 }
2214 
2215 static HRESULT WINAPI IDirectPlay3AImpl_EnumGroups( IDirectPlay3A *iface, GUID *instance,
2216         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2217 {
2218     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2219     return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2220             flags );
2221 }
2222 
2223 static HRESULT WINAPI IDirectPlay3Impl_EnumGroups( IDirectPlay3 *iface, GUID *instance,
2224         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2225 {
2226     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2227     return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2228             flags );
2229 }
2230 
2231 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroups( IDirectPlay4A *iface, GUID *instance,
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 
2245 static HRESULT WINAPI IDirectPlay2AImpl_EnumPlayers( IDirectPlay2A *iface, GUID *instance,
2246         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2247 {
2248     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2249     return IDirectPlayX_EnumPlayers( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
2250             flags );
2251 }
2252 
2253 static HRESULT WINAPI IDirectPlay2Impl_EnumPlayers( IDirectPlay2 *iface, GUID *instance,
2254         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2255 {
2256     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2257     return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2258             flags );
2259 }
2260 
2261 static HRESULT WINAPI IDirectPlay3AImpl_EnumPlayers( IDirectPlay3A *iface, GUID *instance,
2262         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2263 {
2264     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2265     return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2266             flags );
2267 }
2268 
2269 static HRESULT WINAPI IDirectPlay3Impl_EnumPlayers( IDirectPlay3 *iface, GUID *instance,
2270         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2271 {
2272     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2273     return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2274             flags );
2275 }
2276 
2277 static HRESULT WINAPI IDirectPlay4AImpl_EnumPlayers( IDirectPlay4A *iface, GUID *instance,
2278         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2279 {
2280     return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
2281             context, flags );
2282 }
2283 
2284 static HRESULT WINAPI IDirectPlay4Impl_EnumPlayers( IDirectPlay4 *iface, GUID *instance,
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  */
2294 static void DP_InvokeEnumSessionCallbacks
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 
2324 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
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 
2372 static void DP_KillEnumSessionThread( IDirectPlayImpl *This )
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 
2391 static HRESULT WINAPI IDirectPlay2AImpl_EnumSessions( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
2392         DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2393 {
2394     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
2402     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2403     return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
2404             context, flags );
2405 }
2406 
2407 static HRESULT WINAPI IDirectPlay3AImpl_EnumSessions( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
2408         DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2409 {
2410     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
2418     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2419     return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
2420             context, flags );
2421 }
2422 
2423 static HRESULT WINAPI IDirectPlay4AImpl_EnumSessions( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
2424         DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2425 {
2426     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
2434     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
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 
2491     if ( flags & DPENUMSESSIONS_STOPASYNC )
2492     {
2493         DP_KillEnumSessionThread( This );
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              */
2515             hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags,
2516                     &This->dp2->spData );
2517 
2518             if ( SUCCEEDED(hr) )
2519             {
2520                 EnumSessionAsyncCallbackData* data = HeapAlloc( GetProcessHeap(),
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,
2531                             DUPLICATE_SAME_ACCESS ) )
2532                     ERR( "Can't duplicate thread killing handle\n" );
2533 
2534                 TRACE( ": creating EnumSessionsRequest thread\n" );
2535                 This->dp2->hEnumSessionThread = CreateThread( NULL, 0,
2536                         DP_EnumSessionsSendAsyncRequestThread, data, 0, &tid );
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 
2555 static HRESULT WINAPI IDirectPlay2AImpl_GetCaps( IDirectPlay2A *iface, DPCAPS *caps, DWORD flags )
2556 {
2557     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2558     return IDirectPlayX_GetCaps( &This->IDirectPlay4A_iface, caps, flags );
2559 }
2560 
2561 static HRESULT WINAPI IDirectPlay2Impl_GetCaps( IDirectPlay2 *iface, DPCAPS *caps, DWORD flags )
2562 {
2563     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2564     return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
2565 }
2566 
2567 static HRESULT WINAPI IDirectPlay3AImpl_GetCaps( IDirectPlay3A *iface, DPCAPS *caps, DWORD flags )
2568 {
2569     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2570     return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
2571 }
2572 
2573 static HRESULT WINAPI IDirectPlay3Impl_GetCaps( IDirectPlay3 *iface, DPCAPS *caps, DWORD flags )
2574 {
2575     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2576     return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
2577 }
2578 
2579 static HRESULT WINAPI IDirectPlay4AImpl_GetCaps( IDirectPlay4A *iface, DPCAPS *caps, DWORD flags )
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 
2589 static HRESULT WINAPI IDirectPlay2AImpl_GetGroupData( IDirectPlay2A *iface, DPID group, void *data,
2590         DWORD *size, DWORD flags )
2591 {
2592     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
2599     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2600     return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2601 }
2602 
2603 static HRESULT WINAPI IDirectPlay3AImpl_GetGroupData( IDirectPlay3A *iface, DPID group, void *data,
2604         DWORD *size, DWORD flags )
2605 {
2606     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
2613     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2614     return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2615 }
2616 
2617 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupData( IDirectPlay4A *iface, DPID group,
2618         void *data, DWORD *size, DWORD flags )
2619 {
2620     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2621     return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2622 }
2623 
2624 static HRESULT WINAPI IDirectPlay4Impl_GetGroupData( IDirectPlay4 *iface, DPID group,
2625         void *data, DWORD *size, DWORD flags )
2626 {
2627     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
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 
2722 static HRESULT WINAPI IDirectPlay2AImpl_GetGroupName( IDirectPlay2A *iface, DPID group, void *data,
2723         DWORD *size )
2724 {
2725     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
2732     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2733     return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
2734 }
2735 
2736 static HRESULT WINAPI IDirectPlay3AImpl_GetGroupName( IDirectPlay3A *iface, DPID group, void *data,
2737         DWORD *size )
2738 {
2739     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
2746     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2747     return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
2748 }
2749 
2750 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupName( IDirectPlay4A *iface, DPID idGroup,
2751         void *lpData, DWORD *lpdwDataSize )
2752 {
2753     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
2760     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2761     return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2762 }
2763 
2764 static HRESULT WINAPI IDirectPlay2AImpl_GetMessageCount( IDirectPlay2A *iface, DPID player,
2765         DWORD *count )
2766 {
2767     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
2774     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2775     return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
2776 }
2777 
2778 static HRESULT WINAPI IDirectPlay3AImpl_GetMessageCount( IDirectPlay3A *iface, DPID player,
2779         DWORD *count )
2780 {
2781     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
2788     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2789     return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
2790 }
2791 
2792 static HRESULT WINAPI IDirectPlay4AImpl_GetMessageCount( IDirectPlay4A *iface, DPID player,
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 
2804 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerAddress( IDirectPlay2A *iface, DPID player,
2805         void *data, DWORD *size )
2806 {
2807     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
2814     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2815     return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
2816 }
2817 
2818 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerAddress( IDirectPlay3A *iface, DPID player,
2819         void *data, DWORD *size )
2820 {
2821     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
2828     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2829     return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
2830 }
2831 
2832 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAddress( IDirectPlay4A *iface, DPID player,
2833         void *data, DWORD *size )
2834 {
2835     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
2843     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2844     FIXME( "(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2845     return DP_OK;
2846 }
2847 
2848 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerCaps( IDirectPlay2A *iface, DPID player,
2849         DPCAPS *caps, DWORD flags )
2850 {
2851     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
2858     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2859     return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2860 }
2861 
2862 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerCaps( IDirectPlay3A *iface, DPID player,
2863         DPCAPS *caps, DWORD flags )
2864 {
2865     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
2872     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2873     return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2874 }
2875 
2876 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerCaps( IDirectPlay4A *iface, DPID player,
2877         DPCAPS *caps, DWORD flags )
2878 {
2879     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
2886     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2887     DPSP_GETCAPSDATA data;
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 
2909 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerData( IDirectPlay2A *iface, DPID player,
2910         void *data, DWORD *size, DWORD flags )
2911 {
2912     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
2919     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2920     return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2921 }
2922 
2923 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerData( IDirectPlay3A *iface, DPID player,
2924         void *data, DWORD *size, DWORD flags )
2925 {
2926     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
2933     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2934     return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2935 }
2936 
2937 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerData( IDirectPlay4A *iface, DPID player,
2938         void *data, DWORD *size, DWORD flags )
2939 {
2940     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
2947     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2948     lpPlayerList plist;
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 
3049 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerName( IDirectPlay2A *iface, DPID player,
3050         void *data, DWORD *size )
3051 {
3052     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
3059     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3060     return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
3061 }
3062 
3063 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerName( IDirectPlay3A *iface, DPID player,
3064         void *data, DWORD *size )
3065 {
3066     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
3073     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3074     return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
3075 }
3076 
3077 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
3078         void *lpData, DWORD *lpdwDataSize )
3079 {
3080     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
3087     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
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 
3124 static HRESULT WINAPI IDirectPlay2AImpl_GetSessionDesc( IDirectPlay2A *iface, void *data,
3125         DWORD *size )
3126 {
3127     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
3134     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3135     return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
3136 }
3137 
3138 static HRESULT WINAPI IDirectPlay3AImpl_GetSessionDesc( IDirectPlay3A *iface, void *data,
3139         DWORD *size )
3140 {
3141     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
3148     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3149     return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
3150 }
3151 
3152 static HRESULT WINAPI IDirectPlay4AImpl_GetSessionDesc( IDirectPlay4A *iface, void *lpData,
3153         DWORD *lpdwDataSize )
3154 {
3155     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3156     return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
3157 }
3158 
3159 static HRESULT WINAPI IDirectPlay4Impl_GetSessionDesc( IDirectPlay4 *iface, void *lpData,
3160         DWORD *lpdwDataSize )
3161 {
3162     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3163     return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
3164 }
3165 
3166 static HRESULT WINAPI IDirectPlay2AImpl_Initialize( IDirectPlay2A *iface, GUID *guid )
3167 {
3168     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3169     return IDirectPlayX_Initialize( &This->IDirectPlay4A_iface, guid );
3170 }
3171 
3172 static HRESULT WINAPI IDirectPlay2Impl_Initialize( IDirectPlay2 *iface, GUID *guid )
3173 {
3174     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3175     return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
3176 }
3177 
3178 static HRESULT WINAPI IDirectPlay3AImpl_Initialize( IDirectPlay3A *iface, GUID *guid )
3179 {
3180     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3181     return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
3182 }
3183 
3184 static HRESULT WINAPI IDirectPlay3Impl_Initialize( IDirectPlay3 *iface, GUID *guid )
3185 {
3186     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3187     return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
3188 }
3189 
3190 /* Intended only for COM compatibility. Always returns an error. */
3191 static HRESULT WINAPI IDirectPlay4AImpl_Initialize( IDirectPlay4A *iface, GUID *guid )
3192 {
3193     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
3200     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3201     TRACE( "(%p)->(%p): no-op\n", This, guid );
3202     return DPERR_ALREADYINITIALIZED;
3203 }
3204 
3205 
3206 static HRESULT DP_SecureOpen( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpsd, DWORD dwFlags,
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 */
3232   DP_KillEnumSessionThread( This );
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   {
3253     DPSP_OPENDATA data;
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,
3296                              DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
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",
3310          DPLAYX_HresultToString(hr) );
3311   }
3312 
3313   return hr;
3314 }
3315 
3316 static HRESULT WINAPI IDirectPlay2AImpl_Open( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
3317         DWORD flags )
3318 {
3319     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
3326     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3327     return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
3328 }
3329 
3330 static HRESULT WINAPI IDirectPlay3AImpl_Open( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
3331         DWORD flags )
3332 {
3333     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
3340     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3341     return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
3342 }
3343 
3344 static HRESULT WINAPI IDirectPlay4AImpl_Open( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
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 
3356 static HRESULT DP_IF_Receive( IDirectPlayImpl *This, DPID *lpidFrom, DPID *lpidTo, DWORD dwFlags,
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   {
3371     dwFlags = DPRECEIVE_ALL;
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 ) ||
3392            ( dwFlags & DPRECEIVE_FROMPLAYER )
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 
3413 static HRESULT WINAPI IDirectPlay2AImpl_Receive( IDirectPlay2A *iface, DPID *from, DPID *to,
3414         DWORD flags, void *data, DWORD *size )
3415 {
3416     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
3423     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3424     return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
3425 }
3426 
3427 static HRESULT WINAPI IDirectPlay3AImpl_Receive( IDirectPlay3A *iface, DPID *from, DPID *to,
3428         DWORD flags, void *data, DWORD *size )
3429 {
3430     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
3437     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3438     return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
3439 }
3440 
3441 static HRESULT WINAPI IDirectPlay4AImpl_Receive( IDirectPlay4A *iface, DPID *lpidFrom,
3442         DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
3443 {
3444     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
3451     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3452     return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, FALSE );
3453 }
3454 
3455 static HRESULT WINAPI IDirectPlay2AImpl_Send( IDirectPlay2A *iface, DPID from, DPID to,
3456         DWORD flags, void *data, DWORD size )
3457 {
3458     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
3465     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3466     return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
3467 }
3468 
3469 static HRESULT WINAPI IDirectPlay3AImpl_Send( IDirectPlay3A *iface, DPID from, DPID to,
3470         DWORD flags, void *data, DWORD size )
3471 {
3472     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
3479     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3480     return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
3481 }
3482 
3483 static HRESULT WINAPI IDirectPlay4AImpl_Send( IDirectPlay4A *iface, DPID from, DPID to,
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 
3495 static HRESULT WINAPI IDirectPlay2AImpl_SetGroupData( IDirectPlay2A *iface, DPID group, void *data,
3496         DWORD size, DWORD flags )
3497 {
3498     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
3505     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3506     return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
3507 }
3508 
3509 static HRESULT WINAPI IDirectPlay3AImpl_SetGroupData( IDirectPlay3A *iface, DPID group, void *data,
3510         DWORD size, DWORD flags )
3511 {
3512     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
3519     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3520     return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
3521 }
3522 
3523 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupData( IDirectPlay4A *iface, DPID group, void *data,
3524         DWORD size, DWORD flags )
3525 {
3526     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
3533     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
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 
3586 static HRESULT WINAPI IDirectPlay2AImpl_SetGroupName( IDirectPlay2A *iface, DPID group,
3587         DPNAME *name, DWORD flags )
3588 {
3589     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3590     return IDirectPlayX_SetGroupName( &This->IDirectPlay4A_iface, group, name, flags );
3591 }
3592 
3593 static HRESULT WINAPI IDirectPlay2Impl_SetGroupName( IDirectPlay2 *iface, DPID group,
3594         DPNAME *name, DWORD flags )
3595 {
3596     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3597     return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
3598 }
3599 
3600 static HRESULT WINAPI IDirectPlay3AImpl_SetGroupName( IDirectPlay3A *iface, DPID group,
3601         DPNAME *name, DWORD flags )
3602 {
3603     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3604     return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
3605 }
3606 
3607 static HRESULT WINAPI IDirectPlay3Impl_SetGroupName( IDirectPlay3 *iface, DPID group,
3608         DPNAME *name, DWORD flags )
3609 {
3610     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3611     return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
3612 }
3613 
3614 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupName( IDirectPlay4A *iface, DPID idGroup,
3615         DPNAME *lpGroupName, DWORD dwFlags )
3616 {
3617     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
3624     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3625     return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3626 }
3627 
3628 static HRESULT WINAPI IDirectPlay2AImpl_SetPlayerData( IDirectPlay2A *iface, DPID player,
3629         void *data, DWORD size, DWORD flags )
3630 {
3631     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
3638     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3639     return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
3640 }
3641 
3642 static HRESULT WINAPI IDirectPlay3AImpl_SetPlayerData( IDirectPlay3A *iface, DPID player,
3643         void *data, DWORD size, DWORD flags )
3644 {
3645     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
3652     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3653     return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
3654 }
3655 
3656 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerData( IDirectPlay4A *iface, DPID player,
3657         void *data, DWORD size, DWORD flags )
3658 {
3659     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
3666     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3667     lpPlayerList plist;
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 
3724 static HRESULT WINAPI IDirectPlay2AImpl_SetPlayerName( IDirectPlay2A *iface, DPID player,
3725         DPNAME *name, DWORD flags )
3726 {
3727     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
3734     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3735     return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
3736 }
3737 
3738 static HRESULT WINAPI IDirectPlay3AImpl_SetPlayerName( IDirectPlay3A *iface, DPID player,
3739         DPNAME *name, DWORD flags )
3740 {
3741     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
3748     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3749     return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
3750 }
3751 
3752 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
3753         DPNAME *lpPlayerName, DWORD dwFlags )
3754 {
3755     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
3762     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3763     return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3764 }
3765 
3766 static HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
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 
3823 static HRESULT WINAPI IDirectPlay2AImpl_SetSessionDesc( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
3824         DWORD flags )
3825 {
3826     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
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 {
3833     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3834     return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
3835 }
3836 
3837 static HRESULT WINAPI IDirectPlay3AImpl_SetSessionDesc( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
3838         DWORD flags )
3839 {
3840     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
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 {
3847     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3848     return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
3849 }
3850 
3851 static HRESULT WINAPI IDirectPlay4AImpl_SetSessionDesc( IDirectPlay4A *iface,
3852         DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
3853 {
3854     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
3861     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
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 */
3866 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
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 
3963 static HRESULT WINAPI IDirectPlay3AImpl_AddGroupToGroup( IDirectPlay3A *iface, DPID parent,
3964         DPID group )
3965 {
3966     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3967     return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4A_iface, parent, group );
3968 }
3969 
3970 static HRESULT WINAPI IDirectPlay3Impl_AddGroupToGroup( IDirectPlay3 *iface, DPID parent,
3971         DPID group )
3972 {
3973     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3974     return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
3975 }
3976 
3977 static HRESULT WINAPI IDirectPlay4AImpl_AddGroupToGroup( IDirectPlay4A *iface, DPID parent,
3978         DPID group )
3979 {
3980     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3981     return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
3982 }
3983 
3984 static HRESULT WINAPI IDirectPlay4Impl_AddGroupToGroup( IDirectPlay4 *iface, DPID parent,
3985         DPID group )
3986 {
3987     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3988     lpGroupData gdata;
3989     lpGroupList glist;
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   {
4069     DPSP_CREATEGROUPDATA data;
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   {
4087     DPMSG_CREATEPLAYERORGROUP msg;
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 
4107 static HRESULT WINAPI IDirectPlay3AImpl_CreateGroupInGroup( IDirectPlay3A *iface, DPID parent,
4108         DPID *group, DPNAME *name, void *data, DWORD size, DWORD flags )
4109 {
4110     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4111     return IDirectPlayX_CreateGroupInGroup( &This->IDirectPlay4A_iface, parent, group, name,
4112             data, size, flags );
4113 }
4114 
4115 static HRESULT WINAPI IDirectPlay3Impl_CreateGroupInGroup( IDirectPlay3 *iface, DPID parent,
4116         DPID *group, DPNAME *name, void *data, DWORD size, DWORD flags )
4117 {
4118     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4119     return IDirectPlayX_CreateGroupInGroup( &This->IDirectPlay4_iface, parent, group, name,
4120             data, size, flags );
4121 }
4122 
4123 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroupInGroup( IDirectPlay4A *iface,
4124         DPID idParentGroup, DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize,
4125         DWORD dwFlags )
4126 {
4127     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
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 {
4138     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4139 
4140     *lpidGroup = DPID_UNKNOWN;
4141 
4142     return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
4143             dwDataSize, dwFlags, FALSE );
4144 }
4145 
4146 static HRESULT WINAPI IDirectPlay3AImpl_DeleteGroupFromGroup( IDirectPlay3A *iface, DPID parent,
4147         DPID group )
4148 {
4149     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4150     return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4A_iface, parent, group );
4151 }
4152 
4153 static HRESULT WINAPI IDirectPlay3Impl_DeleteGroupFromGroup( IDirectPlay3 *iface, DPID parent,
4154         DPID group )
4155 {
4156     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4157     return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
4158 }
4159 
4160 static HRESULT WINAPI IDirectPlay4AImpl_DeleteGroupFromGroup( IDirectPlay4A *iface, DPID parent,
4161         DPID group )
4162 {
4163     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4164     return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
4165 }
4166 
4167 static HRESULT WINAPI IDirectPlay4Impl_DeleteGroupFromGroup( IDirectPlay4 *iface, DPID parent,
4168         DPID group )
4169 {
4170     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4171     lpGroupList glist;
4172     lpGroupData parentdata;
4173 
4174     TRACE("(%p)->(0x%08x,0x%08x)\n", This, parent, group );
4175 
4176     /* Is the parent group valid? */
4177     if ( ( parentdata = DP_FindAnyGroup(This, parent ) ) == NULL )
4178         return DPERR_INVALIDGROUP;
4179 
4180     /* Remove the group from the parent group queue */
4181     DPQ_REMOVE_ENTRY( parentdata->groups, groups, lpGData->dpid, ==, group, glist );
4182 
4183     if ( glist == NULL )
4184         return DPERR_INVALIDGROUP;
4185 
4186     /* Decrement the ref count */
4187     glist->lpGData->uRef--;
4188 
4189     /* Free up the list item */
4190     HeapFree( GetProcessHeap(), 0, glist );
4191 
4192     /* Should send a DELETEGROUPFROMGROUP message */
4193     FIXME( "message not sent\n" );
4194 
4195     return DP_OK;
4196 }
4197 
4198 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
4199                                     LPDWORD lpdwBufSize )
4200 {
4201   DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
4202   HRESULT                  hr;
4203 
4204   dpCompoundAddress.dwDataSize = sizeof( GUID );
4205   dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
4206   dpCompoundAddress.lpData = lpcSpGuid;
4207 
4208   *lplpAddrBuf = NULL;
4209   *lpdwBufSize = 0;
4210 
4211   hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
4212                                   lpdwBufSize, TRUE );
4213 
4214   if( hr != DPERR_BUFFERTOOSMALL )
4215   {
4216     ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
4217     return FALSE;
4218   }
4219 
4220   /* Now allocate the buffer */
4221   *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4222                             *lpdwBufSize );
4223 
4224   hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
4225                                   lpdwBufSize, TRUE );
4226   if( FAILED(hr) )
4227   {
4228     ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
4229     return FALSE;
4230   }
4231 
4232   return TRUE;
4233 }
4234 
4235 static HRESULT WINAPI IDirectPlay3AImpl_EnumConnections( IDirectPlay3A *iface,
4236         const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
4237 {
4238     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4239     return IDirectPlayX_EnumConnections( &This->IDirectPlay4A_iface, application, enumcb, context,
4240             flags );
4241 }
4242 
4243 static HRESULT WINAPI IDirectPlay3Impl_EnumConnections( IDirectPlay3 *iface,
4244         const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
4245 {
4246     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4247     return IDirectPlayX_EnumConnections( &This->IDirectPlay4_iface, application, enumcb, context,
4248             flags );
4249 }
4250 
4251 static HRESULT WINAPI IDirectPlay4AImpl_EnumConnections( IDirectPlay4A *iface,
4252         const GUID *lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, void *lpContext,
4253         DWORD dwFlags )
4254 {
4255   IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4256   TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
4257 
4258   /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
4259   if( dwFlags == 0 )
4260   {
4261     dwFlags = DPCONNECTION_DIRECTPLAY;
4262   }
4263 
4264   if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
4265           ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
4266     )
4267   {
4268     return DPERR_INVALIDFLAGS;
4269   }
4270 
4271   if( !lpEnumCallback )
4272   {
4273      return DPERR_INVALIDPARAMS;
4274   }
4275 
4276   /* Enumerate DirectPlay service providers */
4277   if( dwFlags & DPCONNECTION_DIRECTPLAY )
4278   {
4279     HKEY hkResult;
4280     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4281     LPCSTR guidDataSubKey  = "Guid";
4282     char subKeyName[51];
4283     DWORD dwIndex, sizeOfSubKeyName=50;
4284     FILETIME filetime;
4285 
4286     /* Need to loop over the service providers in the registry */
4287     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4288                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4289     {
4290       /* Hmmm. Does this mean that there are no service providers? */
4291       ERR(": no service providers?\n");
4292       return DP_OK;
4293     }
4294 
4295 
4296     /* Traverse all the service providers we have available */
4297     for( dwIndex=0;
4298          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4299                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4300          ++dwIndex, sizeOfSubKeyName=51 )
4301     {
4302 
4303       HKEY     hkServiceProvider;
4304       GUID     serviceProviderGUID;
4305       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
4306       char     returnBuffer[51];
4307       WCHAR    buff[51];
4308       DPNAME   dpName;
4309       BOOL     bBuildPass;
4310 
4311       LPVOID                   lpAddressBuffer = NULL;
4312       DWORD                    dwAddressBufferSize = 0;
4313 
4314       TRACE(" this time through: %s\n", subKeyName );
4315 
4316       /* Get a handle for this particular service provider */
4317       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4318                          &hkServiceProvider ) != ERROR_SUCCESS )
4319       {
4320          ERR(": what the heck is going on?\n" );
4321          continue;
4322       }
4323 
4324       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4325                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
4326                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4327       {
4328         ERR(": missing GUID registry data members\n" );
4329         RegCloseKey(hkServiceProvider);
4330         continue;
4331       }
4332       RegCloseKey(hkServiceProvider);
4333 
4334       /* FIXME: Check return types to ensure we're interpreting data right */
4335       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, ARRAY_SIZE( buff ));
4336       CLSIDFromString( buff, &serviceProviderGUID );
4337       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4338 
4339       /* Fill in the DPNAME struct for the service provider */
4340       dpName.dwSize             = sizeof( dpName );
4341       dpName.dwFlags            = 0;
4342       dpName.u1.lpszShortNameA = subKeyName;
4343       dpName.u2.lpszLongNameA  = NULL;
4344 
4345       /* Create the compound address for the service provider.
4346        * NOTE: This is a gruesome architectural scar right now.  DP
4347        * uses DPL and DPL uses DP.  Nasty stuff. This may be why the
4348        * native dll just gets around this little bit by allocating an
4349        * 80 byte buffer which isn't even filled with a valid compound
4350        * address. Oh well. Creating a proper compound address is the
4351        * way to go anyways despite this method taking slightly more
4352        * heap space and realtime :) */
4353 
4354       bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
4355                                            &lpAddressBuffer,
4356                                            &dwAddressBufferSize );
4357       if( !bBuildPass )
4358       {
4359         ERR( "Can't build compound addr\n" );
4360         return DPERR_GENERIC;
4361       }
4362 
4363       /* The enumeration will return FALSE if we are not to continue */
4364       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
4365                            &dpName, dwFlags, lpContext ) )
4366       {
4367          HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4368          return DP_OK;
4369       }
4370       HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4371     }
4372   }
4373 
4374   /* Enumerate DirectPlayLobby service providers */
4375   if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
4376   {
4377     HKEY hkResult;
4378     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4379     LPCSTR guidDataSubKey  = "Guid";
4380     char subKeyName[51];
4381     DWORD dwIndex, sizeOfSubKeyName=50;
4382     FILETIME filetime;
4383 
4384     /* Need to loop over the service providers in the registry */
4385     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4386                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4387     {
4388       TRACE("No Lobby Providers have been registered.\n");
4389       return DP_OK;
4390     }
4391 
4392 
4393     /* Traverse all the lobby providers we have available */
4394     for( dwIndex=0;
4395          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4396                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4397          ++dwIndex, sizeOfSubKeyName=51 )
4398     {
4399 
4400       HKEY     hkServiceProvider;
4401       GUID     serviceProviderGUID;
4402       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
4403       char     returnBuffer[51];
4404       WCHAR    buff[51];
4405       DPNAME   dpName;
4406       HRESULT  hr;
4407 
4408       DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
4409       LPVOID                   lpAddressBuffer = NULL;
4410       DWORD                    dwAddressBufferSize = 0;
4411 
4412       TRACE(" this time through: %s\n", subKeyName );
4413 
4414       /* Get a handle for this particular service provider */
4415       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4416                          &hkServiceProvider ) != ERROR_SUCCESS )
4417       {
4418          ERR(": what the heck is going on?\n" );
4419          continue;
4420       }
4421 
4422       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4423                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
4424                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4425       {
4426         ERR(": missing GUID registry data members\n" );
4427         RegCloseKey(hkServiceProvider);
4428         continue;
4429       }
4430       RegCloseKey(hkServiceProvider);
4431 
4432       /* FIXME: Check return types to ensure we're interpreting data right */
4433       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, ARRAY_SIZE( buff ));
4434       CLSIDFromString( buff, &serviceProviderGUID );
4435       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4436 
4437       /* Fill in the DPNAME struct for the service provider */
4438       dpName.dwSize             = sizeof( dpName );
4439       dpName.dwFlags            = 0;
4440       dpName.u1.lpszShortNameA = subKeyName;
4441       dpName.u2.lpszLongNameA  = NULL;
4442 
4443       /* Create the compound address for the service provider.
4444          NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
4445                nast stuff. This may be why the native dll just gets around this little bit by
4446                allocating an 80 byte buffer which isn't even a filled with a valid compound
4447                address. Oh well. Creating a proper compound address is the way to go anyways
4448                despite this method taking slightly more heap space and realtime :) */
4449 
4450       dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
4451       dpCompoundAddress.dwDataSize   = sizeof( GUID );
4452       dpCompoundAddress.lpData       = &serviceProviderGUID;
4453 
4454       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
4455                                      &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
4456       {
4457         ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
4458         return hr;
4459       }
4460 
4461       /* Now allocate the buffer */
4462       lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
4463 
4464       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
4465                                      &dwAddressBufferSize, TRUE ) ) != DP_OK )
4466       {
4467         ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
4468         HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4469         return hr;
4470       }
4471 
4472       /* The enumeration will return FALSE if we are not to continue */
4473       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
4474                            &dpName, dwFlags, lpContext ) )
4475       {
4476          HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4477          return DP_OK;
4478       }
4479       HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4480     }
4481   }
4482 
4483   return DP_OK;
4484 }
4485 
4486 static HRESULT WINAPI IDirectPlay4Impl_EnumConnections( IDirectPlay4 *iface,
4487         const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
4488 {
4489     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4490     return IDirectPlayX_EnumConnections( &This->IDirectPlay4A_iface, application, enumcb, context,
4491             flags );
4492 }
4493 
4494 static HRESULT WINAPI IDirectPlay3AImpl_EnumGroupsInGroup( IDirectPlay3A *iface, DPID group,
4495         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
4496 {
4497     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4498     return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4A_iface, group, instance,
4499             enumplayercb, context, flags );
4500 }
4501 
4502 static HRESULT WINAPI IDirectPlay3Impl_EnumGroupsInGroup( IDirectPlay3 *iface, DPID group,
4503         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
4504 {
4505     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4506     return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, group, instance,
4507             enumplayercb, context, flags );
4508 }
4509 
4510 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupsInGroup( IDirectPlay4A *iface, DPID group,
4511         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
4512 {
4513     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4514     return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, group, instance,
4515             enumplayercb, context, flags );
4516 }
4517 
4518 static HRESULT WINAPI IDirectPlay4Impl_EnumGroupsInGroup( IDirectPlay4 *iface, DPID group,
4519         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
4520 {
4521     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4522     lpGroupList glist;
4523     lpGroupData gdata;
4524 
4525     FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
4526             context, flags );
4527 
4528     if ( This->dp2->connectionInitialized == NO_PROVIDER )
4529         return DPERR_UNINITIALIZED;
4530 
4531     if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
4532         return DPERR_INVALIDGROUP;
4533 
4534     if ( DPQ_IS_EMPTY( gdata->groups ) )
4535         return DP_OK;
4536 
4537 
4538     for( glist = DPQ_FIRST( gdata->groups ); ; glist = DPQ_NEXT( glist->groups ) )
4539     {
4540         /* FIXME: Should check flags for match here */
4541         if ( !(*enumplayercb)( glist->lpGData->dpid, DPPLAYERTYPE_GROUP, &glist->lpGData->name,
4542                     flags, context ) )
4543             return DP_OK; /* User requested break */
4544 
4545         if ( DPQ_IS_ENDOFLIST( glist->groups ) )
4546             break;
4547     }
4548 
4549     return DP_OK;
4550 }
4551 
4552 static HRESULT WINAPI IDirectPlay3AImpl_GetGroupConnectionSettings( IDirectPlay3A *iface,
4553         DWORD flags, DPID group, void *data, DWORD *size )
4554 {
4555     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4556     return IDirectPlayX_GetGroupConnectionSettings( &This->IDirectPlay4A_iface, flags, group,
4557             data, size );
4558 }
4559 
4560 static HRESULT WINAPI IDirectPlay3Impl_GetGroupConnectionSettings( IDirectPlay3 *iface,
4561         DWORD flags, DPID group, void *data, DWORD *size )
4562 {
4563     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4564     return IDirectPlayX_GetGroupConnectionSettings( &This->IDirectPlay4_iface, flags, group,
4565             data, size );
4566 }
4567 
4568 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupConnectionSettings( IDirectPlay4A *iface,
4569         DWORD flags, DPID group, void *data, DWORD *size )
4570 {
4571     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4572     FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
4573     return DP_OK;
4574 }
4575 
4576 static HRESULT WINAPI IDirectPlay4Impl_GetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
4577         DPID group, void *data, DWORD *size )
4578 {
4579     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4580     FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
4581     return DP_OK;
4582 }
4583 
4584 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4585     REFGUID         guidDataType,
4586     DWORD           dwDataSize,
4587     LPCVOID         lpData,
4588     LPVOID          lpContext )
4589 {
4590   /* Looking for the GUID of the provider to load */
4591   if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
4592       ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4593     )
4594   {
4595     TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4596            debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4597 
4598     if( dwDataSize != sizeof( GUID ) )
4599     {
4600       ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4601     }
4602 
4603     memcpy( lpContext, lpData, dwDataSize );
4604 
4605     /* There shouldn't be more than 1 GUID/compound address */
4606     return FALSE;
4607   }
4608 
4609   /* Still waiting for what we want */
4610   return TRUE;
4611 }
4612 
4613 
4614 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4615 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4616 {
4617   UINT i;
4618   LPCSTR spSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4619   LPCSTR lpSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4620   LPCSTR guidDataSubKey   = "Guid";
4621   LPCSTR majVerDataSubKey = "dwReserved1";
4622   LPCSTR minVerDataSubKey = "dwReserved2";
4623   LPCSTR pathSubKey       = "Path";
4624 
4625   TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4626 
4627   /* FIXME: Cloned code with a quick hack. */
4628   for( i=0; i<2; i++ )
4629   {
4630     HKEY hkResult;
4631     LPCSTR searchSubKey;
4632     char subKeyName[51];
4633     DWORD dwIndex, sizeOfSubKeyName=50;
4634     FILETIME filetime;
4635 
4636     (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4637     *lpbIsDpSp = (i == 0);
4638 
4639 
4640     /* Need to loop over the service providers in the registry */
4641     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4642                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4643     {
4644       /* Hmmm. Does this mean that there are no service providers? */
4645       ERR(": no service providers?\n");
4646       return 0;
4647     }
4648 
4649     /* Traverse all the service providers we have available */
4650     for( dwIndex=0;
4651          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4652                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4653          ++dwIndex, sizeOfSubKeyName=51 )
4654     {
4655 
4656       HKEY     hkServiceProvider;
4657       GUID     serviceProviderGUID;
4658       DWORD    returnType, sizeOfReturnBuffer = 255;
4659       char     returnBuffer[256];
4660       WCHAR    buff[51];
4661       DWORD    dwTemp, len;
4662 
4663       TRACE(" this time through: %s\n", subKeyName );
4664 
4665       /* Get a handle for this particular service provider */
4666       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4667                          &hkServiceProvider ) != ERROR_SUCCESS )
4668       {
4669          ERR(": what the heck is going on?\n" );
4670          continue;
4671       }
4672 
4673       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4674                             NULL, &returnType, (LPBYTE)returnBuffer,
4675                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4676       {
4677         ERR(": missing GUID registry data members\n" );
4678         continue;
4679       }
4680 
4681       /* FIXME: Check return types to ensure we're interpreting data right */
4682       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, ARRAY_SIZE( buff ));
4683       CLSIDFromString( buff, &serviceProviderGUID );
4684       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4685 
4686       /* Determine if this is the Service Provider that the user asked for */
4687       if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4688       {
4689         continue;
4690       }
4691 
4692       if( i == 0 ) /* DP SP */
4693       {
4694         len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4695         lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4696         MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4697       }
4698 
4699       sizeOfReturnBuffer = 255;
4700 
4701       /* Get dwReserved1 */
4702       if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4703                             NULL, &returnType, (LPBYTE)returnBuffer,
4704                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4705       {
4706          ERR(": missing dwReserved1 registry data members\n") ;
4707          continue;
4708       }
4709 
4710       if( i == 0 )
4711           memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4712 
4713       sizeOfReturnBuffer = 255;
4714 
4715       /* Get dwReserved2 */
4716       if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4717                             NULL, &returnType, (LPBYTE)returnBuffer,
4718                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4719       {
4720          ERR(": missing dwReserved1 registry data members\n") ;
4721          continue;
4722       }
4723 
4724       if( i == 0 )
4725           memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4726 
4727       sizeOfReturnBuffer = 255;
4728 
4729       /* Get the path for this service provider */
4730       if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4731                             NULL, NULL, (LPBYTE)returnBuffer,
4732                             &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4733       {
4734         ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4735         continue;
4736       }
4737 
4738       TRACE( "Loading %s\n", returnBuffer );
4739       return LoadLibraryA( returnBuffer );
4740     }
4741   }
4742 
4743   return 0;
4744 }
4745 
4746 static HRESULT DP_InitializeDPSP( IDirectPlayImpl *This, HMODULE hServiceProvider )
4747 {
4748   HRESULT hr;
4749   LPDPSP_SPINIT SPInit;
4750 
4751   /* Initialize the service provider by calling SPInit */
4752   SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4753 
4754   if( SPInit == NULL )
4755   {
4756     ERR( "Service provider doesn't provide SPInit interface?\n" );
4757     FreeLibrary( hServiceProvider );
4758     return DPERR_UNAVAILABLE;
4759   }
4760 
4761   TRACE( "Calling SPInit (DP SP entry point)\n" );
4762 
4763   hr = (*SPInit)( &This->dp2->spData );
4764 
4765   if( FAILED(hr) )
4766   {
4767     ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4768     FreeLibrary( hServiceProvider );
4769     return hr;
4770   }
4771 
4772   /* FIXME: Need to verify the sanity of the returned callback table
4773    *        using IsBadCodePtr */
4774   This->dp2->bSPInitialized = TRUE;
4775 
4776   /* This interface is now initialized as a DP object */
4777   This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4778 
4779   /* Store the handle of the module so that we can unload it later */
4780   This->dp2->hServiceProvider = hServiceProvider;
4781 
4782   return hr;
4783 }
4784 
4785 static HRESULT DP_InitializeDPLSP( IDirectPlayImpl *This, HMODULE hLobbyProvider )
4786 {
4787   HRESULT hr;
4788   LPSP_INIT DPLSPInit;
4789 
4790   /* Initialize the service provider by calling SPInit */
4791   DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4792 
4793   if( DPLSPInit == NULL )
4794   {
4795     ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4796     FreeLibrary( hLobbyProvider );
4797     return DPERR_UNAVAILABLE;
4798   }
4799 
4800   TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4801 
4802   hr = (*DPLSPInit)( &This->dp2->dplspData );
4803 
4804   if( FAILED(hr) )
4805   {
4806     ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4807     FreeLibrary( hLobbyProvider );
4808     return hr;
4809   }
4810 
4811   /* FIXME: Need to verify the sanity of the returned callback table
4812    *        using IsBadCodePtr */
4813 
4814   This->dp2->bDPLSPInitialized = TRUE;
4815 
4816   /* This interface is now initialized as a lobby object */
4817   This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4818 
4819   /* Store the handle of the module so that we can unload it later */
4820   This->dp2->hDPLobbyProvider = hLobbyProvider;
4821 
4822   return hr;
4823 }
4824 
4825 static HRESULT WINAPI IDirectPlay3AImpl_InitializeConnection( IDirectPlay3A *iface,
4826         void *connection, DWORD flags )
4827 {
4828     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4829     return IDirectPlayX_InitializeConnection( &This->IDirectPlay4A_iface, connection, flags );
4830 }
4831 
4832 static HRESULT WINAPI IDirectPlay3Impl_InitializeConnection( IDirectPlay3 *iface,
4833         void *connection, DWORD flags )
4834 {
4835     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4836     return IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, flags );
4837 }
4838 
4839 static HRESULT WINAPI IDirectPlay4AImpl_InitializeConnection( IDirectPlay4A *iface,
4840         void *connection, DWORD flags )
4841 {
4842     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4843     return IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, flags );
4844 }
4845 
4846 static HRESULT WINAPI IDirectPlay4Impl_InitializeConnection( IDirectPlay4 *iface,
4847         void *connection, DWORD flags )
4848 {
4849     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4850     HMODULE servprov;
4851     GUID sp;
4852     const DWORD size = 80; /* FIXME: Need to calculate it correctly */
4853     BOOL is_dp_sp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4854     HRESULT hr;
4855 
4856     TRACE( "(%p)->(%p,0x%08x)\n", This, connection, flags );
4857 
4858     if ( !connection )
4859         return DPERR_INVALIDPARAMS;
4860 
4861     if ( flags )
4862         return DPERR_INVALIDFLAGS;
4863 
4864     if ( This->dp2->connectionInitialized != NO_PROVIDER )
4865         return DPERR_ALREADYINITIALIZED;
4866 
4867     /* Find out what the requested SP is and how large this buffer is */
4868     hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, connection, size, &sp );
4869 
4870     if ( FAILED(hr) )
4871     {
4872         ERR( "Invalid compound address?\n" );
4873         return DPERR_UNAVAILABLE;
4874     }
4875 
4876     /* Load the service provider */
4877     servprov = DP_LoadSP( &sp, &This->dp2->spData, &is_dp_sp );
4878 
4879     if ( !servprov )
4880     {
4881         ERR( "Unable to load service provider %s\n", debugstr_guid(&sp) );
4882         return DPERR_UNAVAILABLE;
4883     }
4884 
4885     if ( is_dp_sp )
4886     {
4887          /* Fill in what we can of the Service Provider required information.
4888           * The rest was be done in DP_LoadSP
4889           */
4890          This->dp2->spData.lpAddress = connection;
4891          This->dp2->spData.dwAddressSize = size;
4892          This->dp2->spData.lpGuid = &sp;
4893          hr = DP_InitializeDPSP( This, servprov );
4894     }
4895     else
4896     {
4897          This->dp2->dplspData.lpAddress = connection;
4898          hr = DP_InitializeDPLSP( This, servprov );
4899     }
4900 
4901     if ( FAILED(hr) )
4902         return hr;
4903 
4904     return DP_OK;
4905 }
4906 
4907 static HRESULT WINAPI IDirectPlay3AImpl_SecureOpen( IDirectPlay3A *iface,
4908         const DPSESSIONDESC2 *sdesc, DWORD flags, const DPSECURITYDESC *security,
4909         const DPCREDENTIALS *credentials )
4910 {
4911     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4912     return IDirectPlayX_SecureOpen( &This->IDirectPlay4A_iface, sdesc, flags, security,
4913             credentials );
4914 }
4915 
4916 static HRESULT WINAPI IDirectPlay3Impl_SecureOpen( IDirectPlay3 *iface,
4917         const DPSESSIONDESC2 *sdesc, DWORD flags, const DPSECURITYDESC *security,
4918         const DPCREDENTIALS *credentials )
4919 {
4920     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4921     return IDirectPlayX_SecureOpen( &This->IDirectPlay4_iface, sdesc, flags, security,
4922             credentials );
4923 }
4924 
4925 static HRESULT WINAPI IDirectPlay4AImpl_SecureOpen( IDirectPlay4A *iface,
4926         const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
4927         const DPCREDENTIALS *lpCredentials )
4928 {
4929     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4930     return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4931 }
4932 
4933 static HRESULT WINAPI IDirectPlay4Impl_SecureOpen( IDirectPlay4 *iface,
4934         const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
4935         const DPCREDENTIALS *lpCredentials )
4936 {
4937     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4938     return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4939 }
4940 
4941 static HRESULT WINAPI IDirectPlay3AImpl_SendChatMessage( IDirectPlay3A *iface, DPID from, DPID to,
4942         DWORD flags, DPCHAT *chatmsg )
4943 {
4944     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4945     return IDirectPlayX_SendChatMessage( &This->IDirectPlay4A_iface, from, to, flags, chatmsg );
4946 }
4947 
4948 static HRESULT WINAPI IDirectPlay3Impl_SendChatMessage( IDirectPlay3 *iface, DPID from, DPID to,
4949         DWORD flags, DPCHAT *chatmsg )
4950 {
4951     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4952     return IDirectPlayX_SendChatMessage( &This->IDirectPlay4_iface, from, to, flags, chatmsg );
4953 }
4954 
4955 static HRESULT WINAPI IDirectPlay4AImpl_SendChatMessage( IDirectPlay4A *iface, DPID from,
4956         DPID to, DWORD flags, DPCHAT *chatmsg )
4957 {
4958     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4959     FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
4960     return DP_OK;
4961 }
4962 
4963 static HRESULT WINAPI IDirectPlay4Impl_SendChatMessage( IDirectPlay4 *iface, DPID from, DPID to,
4964         DWORD flags, DPCHAT *chatmsg )
4965 {
4966     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4967     FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
4968     return DP_OK;
4969 }
4970 
4971 static HRESULT WINAPI IDirectPlay3AImpl_SetGroupConnectionSettings( IDirectPlay3A *iface,
4972         DWORD flags, DPID group, DPLCONNECTION *connection )
4973 {
4974     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4975     return IDirectPlayX_SetGroupConnectionSettings( &This->IDirectPlay4A_iface, flags, group,
4976             connection );
4977 }
4978 
4979 static HRESULT WINAPI IDirectPlay3Impl_SetGroupConnectionSettings( IDirectPlay3 *iface,
4980         DWORD flags, DPID group, DPLCONNECTION *connection )
4981 {
4982     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4983     return IDirectPlayX_SetGroupConnectionSettings( &This->IDirectPlay4_iface, flags, group,
4984             connection );
4985 }
4986 
4987 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupConnectionSettings( IDirectPlay4A *iface,
4988         DWORD flags, DPID group, DPLCONNECTION *connection )
4989 {
4990     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4991     FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
4992     return DP_OK;
4993 }
4994 
4995 static HRESULT WINAPI IDirectPlay4Impl_SetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
4996         DPID group, DPLCONNECTION *connection )
4997 {
4998     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4999     FIXME( "(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
5000     return DP_OK;
5001 }
5002 
5003 static HRESULT WINAPI IDirectPlay3AImpl_StartSession( IDirectPlay3A *iface, DWORD flags,
5004         DPID group )
5005 {
5006     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
5007     return IDirectPlayX_StartSession( &This->IDirectPlay4A_iface, flags, group );
5008 }
5009 
5010 static HRESULT WINAPI IDirectPlay3Impl_StartSession( IDirectPlay3 *iface, DWORD flags,
5011         DPID group )
5012 {
5013     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
5014     return IDirectPlayX_StartSession( &This->IDirectPlay4_iface, flags, group );
5015 }
5016 
5017 static HRESULT WINAPI IDirectPlay4AImpl_StartSession( IDirectPlay4A *iface, DWORD flags,
5018         DPID group )
5019 {
5020     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5021     return IDirectPlayX_StartSession( &This->IDirectPlay4_iface, flags, group );
5022 }
5023 
5024 static HRESULT WINAPI IDirectPlay4Impl_StartSession( IDirectPlay4 *iface, DWORD flags, DPID group )
5025 {
5026     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5027     FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, flags, group );
5028     return DP_OK;
5029 }
5030 
5031 static HRESULT WINAPI IDirectPlay3AImpl_GetGroupFlags( IDirectPlay3A *iface, DPID group,
5032         DWORD *flags )
5033 {
5034     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
5035     return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4A_iface, group, flags );
5036 }
5037 
5038 static HRESULT WINAPI IDirectPlay3Impl_GetGroupFlags( IDirectPlay3 *iface, DPID group,
5039         DWORD *flags )
5040 {
5041     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
5042     return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4_iface, group, flags );
5043 }
5044 
5045 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupFlags( IDirectPlay4A *iface, DPID group,
5046         DWORD *flags )
5047 {
5048     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5049     return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4_iface, group, flags );
5050 }
5051 
5052 static HRESULT WINAPI IDirectPlay4Impl_GetGroupFlags( IDirectPlay4 *iface, DPID group,
5053         DWORD *flags )
5054 {
5055     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5056     FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, flags );
5057     return DP_OK;
5058 }
5059 
5060 static HRESULT WINAPI IDirectPlay3AImpl_GetGroupParent( IDirectPlay3A *iface, DPID group,
5061         DPID *parent )
5062 {
5063     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
5064     return IDirectPlayX_GetGroupParent( &This->IDirectPlay4A_iface, group, parent );
5065 }
5066 
5067 static HRESULT WINAPI IDirectPlay3Impl_GetGroupParent( IDirectPlay3 *iface, DPID group,
5068         DPID *parent )
5069 {
5070     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
5071     return IDirectPlayX_GetGroupParent( &This->IDirectPlay4_iface, group, parent );
5072 }
5073 
5074 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupParent( IDirectPlay4A *iface, DPID group,
5075         DPID *parent )
5076 {
5077     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5078     return IDirectPlayX_GetGroupParent( &This->IDirectPlay4_iface, group, parent );
5079 }
5080 
5081 static HRESULT WINAPI IDirectPlay4Impl_GetGroupParent( IDirectPlay4 *iface, DPID group,
5082         DPID *parent )
5083 {
5084     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5085     lpGroupData gdata;
5086 
5087     TRACE( "(%p)->(0x%08x,%p)\n", This, group, parent );
5088 
5089     if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
5090         return DPERR_INVALIDGROUP;
5091 
5092     *parent = gdata->dpid;
5093 
5094     return DP_OK;
5095 }
5096 
5097 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerAccount( IDirectPlay3A *iface, DPID player,
5098         DWORD flags, void *data, DWORD *size )
5099 {
5100     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
5101     return IDirectPlayX_GetPlayerAccount( &This->IDirectPlay4A_iface, player, flags, data, size );
5102 }
5103 
5104 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerAccount( IDirectPlay3 *iface, DPID player,
5105         DWORD flags, void *data, DWORD *size )
5106 {
5107     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
5108     return IDirectPlayX_GetPlayerAccount( &This->IDirectPlay4_iface, player, flags, data, size );
5109 }
5110 
5111 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAccount( IDirectPlay4A *iface, DPID player,
5112         DWORD flags, void *data, DWORD *size )
5113 {
5114     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5115     FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
5116     return DP_OK;
5117 }
5118 
5119 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAccount( IDirectPlay4 *iface, DPID player,
5120         DWORD flags, void *data, DWORD *size )
5121 {
5122     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5123     FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
5124     return DP_OK;
5125 }
5126 
5127 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerFlags( IDirectPlay3A *iface, DPID player,
5128         DWORD *flags )
5129 {
5130     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
5131     return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4A_iface, player, flags );
5132 }
5133 
5134 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerFlags( IDirectPlay3 *iface, DPID player,
5135         DWORD *flags )
5136 {
5137     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
5138     return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4_iface, player, flags );
5139 }
5140 
5141 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerFlags( IDirectPlay4A *iface, DPID player,
5142         DWORD *flags )
5143 {
5144     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5145     return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4_iface, player, flags );
5146 }
5147 
5148 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerFlags( IDirectPlay4 *iface, DPID player,
5149         DWORD *flags )
5150 {
5151     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5152     FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, flags );
5153     return DP_OK;
5154 }
5155 
5156 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupOwner( IDirectPlay4A *iface, DPID group,
5157         DPID *owner )
5158 {
5159     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5160     return IDirectPlayX_GetGroupOwner( &This->IDirectPlay4_iface, group, owner );
5161 }
5162 
5163 static HRESULT WINAPI IDirectPlay4Impl_GetGroupOwner( IDirectPlay4 *iface, DPID group,
5164         DPID *owner )
5165 {
5166     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5167     FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, owner );
5168     return DP_OK;
5169 }
5170 
5171 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupOwner( IDirectPlay4A *iface, DPID group,
5172         DPID owner )
5173 {
5174     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5175     return IDirectPlayX_SetGroupOwner( &This->IDirectPlay4_iface, group, owner );
5176 }
5177 
5178 static HRESULT WINAPI IDirectPlay4Impl_SetGroupOwner( IDirectPlay4 *iface, DPID group ,
5179         DPID owner )
5180 {
5181     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5182     FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, owner );
5183     return DP_OK;
5184 }
5185 
5186 static HRESULT WINAPI IDirectPlay4AImpl_SendEx( IDirectPlay4A *iface, DPID from, DPID to,
5187         DWORD flags, void *data, DWORD size, DWORD priority, DWORD timeout, void *context,
5188         DWORD *msgid )
5189 {
5190     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5191     return IDirectPlayX_SendEx( &This->IDirectPlay4_iface, from, to, flags, data, size, priority,
5192             timeout, context, msgid );
5193 }
5194 
5195 static HRESULT WINAPI IDirectPlay4Impl_SendEx( IDirectPlay4 *iface, DPID from, DPID to,
5196         DWORD flags, void *data, DWORD size, DWORD priority, DWORD timeout, void *context,
5197         DWORD *msgid )
5198 {
5199     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5200 
5201     FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p): semi-stub\n",
5202             This, from, to, flags, data, size, priority, timeout, context, msgid );
5203 
5204     if ( This->dp2->connectionInitialized == NO_PROVIDER )
5205         return DPERR_UNINITIALIZED;
5206 
5207     /* FIXME: Add parameter checking */
5208     /* FIXME: First call to this needs to acquire a message id which will be
5209      *        used for multiple sends
5210      */
5211 
5212     /* NOTE: Can't send messages to yourself - this will be trapped in receive */
5213 
5214     /* Verify that the message is being sent from a valid local player. The
5215      * from player may be anonymous DPID_UNKNOWN
5216      */
5217     if ( from != DPID_UNKNOWN && !DP_FindPlayer( This, from ) )
5218     {
5219         WARN( "INFO: Invalid from player 0x%08x\n", from );
5220         return DPERR_INVALIDPLAYER;
5221     }
5222 
5223     /* Verify that the message is being sent to a valid player, group or to
5224      * everyone. If it's valid, send it to those players.
5225      */
5226     if ( to == DPID_ALLPLAYERS )
5227     {
5228         /* See if SP has the ability to multicast. If so, use it */
5229         if ( This->dp2->spData.lpCB->SendToGroupEx )
5230             FIXME( "Use group sendex to group 0\n" );
5231         else if ( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
5232             FIXME( "Use obsolete group send to group 0\n" );
5233         else /* No multicast, multiplicate */
5234             FIXME( "Send to all players using EnumPlayersInGroup\n" );
5235     }
5236     else if ( DP_FindPlayer( This, to ) )
5237     {
5238         /* Have the service provider send this message */
5239         /* FIXME: Could optimize for local interface sends */
5240         return DP_SP_SendEx( This, flags, data, size, priority, timeout, context, msgid );
5241     }
5242     else if ( DP_FindAnyGroup( This, to ) )
5243     {
5244         /* See if SP has the ability to multicast. If so, use it */
5245         if ( This->dp2->spData.lpCB->SendToGroupEx )
5246             FIXME( "Use group sendex\n" );
5247         else if ( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
5248             FIXME( "Use obsolete group send to group\n" );
5249         else /* No multicast, multiplicate */
5250             FIXME( "Send to all players using EnumPlayersInGroup\n" );
5251 
5252     }
5253     else
5254         return DPERR_INVALIDPLAYER;
5255 
5256     /* FIXME: Should return what the send returned */
5257     return DP_OK;
5258 }
5259 
5260 static HRESULT DP_SP_SendEx( IDirectPlayImpl *This, DWORD dwFlags, void *lpData, DWORD dwDataSize,
5261         DWORD dwPriority, DWORD dwTimeout, void *lpContext, DWORD *lpdwMsgID )
5262 {
5263   LPDPMSG lpMElem;
5264 
5265   FIXME( ": stub\n" );
5266 
5267   /* FIXME: This queuing should only be for async messages */
5268 
5269   lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
5270   lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
5271 
5272   CopyMemory( lpMElem->msg, lpData, dwDataSize );
5273 
5274   /* FIXME: Need to queue based on priority */
5275   DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
5276 
5277   return DP_OK;
5278 }
5279 
5280 static HRESULT WINAPI IDirectPlay4AImpl_GetMessageQueue( IDirectPlay4A *iface, DPID from, DPID to,
5281         DWORD flags, DWORD *msgs, DWORD *bytes )
5282 {
5283     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5284     return IDirectPlayX_GetMessageQueue( &This->IDirectPlay4_iface, from, to, flags, msgs, bytes );
5285 }
5286 
5287 static HRESULT WINAPI IDirectPlay4Impl_GetMessageQueue( IDirectPlay4 *iface, DPID from, DPID to,
5288         DWORD flags, DWORD *msgs, DWORD *bytes )
5289 {
5290     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5291     HRESULT hr = DP_OK;
5292 
5293     FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p): semi-stub\n", This, from, to, flags, msgs, bytes );
5294 
5295     /* FIXME: Do we need to do from and to sanity checking here? */
5296     /* FIXME: What about sends which are not immediate? */
5297 
5298     if ( This->dp2->spData.lpCB->GetMessageQueue )
5299     {
5300         DPSP_GETMESSAGEQUEUEDATA data;
5301 
5302         FIXME( "Calling SP GetMessageQueue - is it right?\n" );
5303 
5304         /* FIXME: None of this is documented :( */
5305         data.lpISP        = This->dp2->spData.lpISP;
5306         data.dwFlags      = flags;
5307         data.idFrom       = from;
5308         data.idTo         = to;
5309         data.lpdwNumMsgs  = msgs;
5310         data.lpdwNumBytes = bytes;
5311 
5312         hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
5313     }
5314     else
5315         FIXME( "No SP for GetMessageQueue - fake some data\n" );
5316 
5317     return hr;
5318 }
5319 
5320 static HRESULT dplay_cancelmsg ( IDirectPlayImpl* This, DWORD msgid, DWORD flags, DWORD minprio,
5321         DWORD maxprio )
5322 {
5323     HRESULT hr = DP_OK;
5324 
5325     FIXME( "(%p)->(0x%08x,0x%08x): semi stub\n", This, msgid, flags );
5326 
5327     if ( This->dp2->spData.lpCB->Cancel )
5328     {
5329         DPSP_CANCELDATA data;
5330 
5331         TRACE( "Calling SP Cancel\n" );
5332 
5333         /* FIXME: Undocumented callback */
5334 
5335         data.lpISP          = This->dp2->spData.lpISP;
5336         data.dwFlags        = flags;
5337         data.lprglpvSPMsgID = NULL;
5338         data.cSPMsgID       = msgid;
5339         data.dwMinPriority  = minprio;
5340         data.dwMaxPriority  = maxprio;
5341 
5342         hr = (*This->dp2->spData.lpCB->Cancel)( &data );
5343     }
5344     else
5345         FIXME( "SP doesn't implement Cancel\n" );
5346 
5347     return hr;
5348 }
5349 
5350 static HRESULT WINAPI IDirectPlay4AImpl_CancelMessage( IDirectPlay4A *iface, DWORD msgid,
5351         DWORD flags )
5352 {
5353     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5354     return IDirectPlayX_CancelMessage( &This->IDirectPlay4_iface, msgid, flags );
5355 }
5356 
5357 static HRESULT WINAPI IDirectPlay4Impl_CancelMessage( IDirectPlay4 *iface, DWORD msgid,
5358         DWORD flags )
5359 {
5360     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5361 
5362     if ( flags != 0 )
5363       return DPERR_INVALIDFLAGS;
5364 
5365     if ( msgid == 0 )
5366       flags |= DPCANCELSEND_ALL;
5367 
5368     return dplay_cancelmsg( This, msgid, flags, 0, 0 );
5369 }
5370 
5371 static HRESULT WINAPI IDirectPlay4AImpl_CancelPriority( IDirectPlay4A *iface, DWORD minprio,
5372         DWORD maxprio, DWORD flags )
5373 {
5374     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5375     return IDirectPlayX_CancelPriority( &This->IDirectPlay4_iface, minprio, maxprio, flags );
5376 }
5377 
5378 static HRESULT WINAPI IDirectPlay4Impl_CancelPriority( IDirectPlay4 *iface, DWORD minprio,
5379         DWORD maxprio, DWORD flags )
5380 {
5381     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5382 
5383     if ( flags != 0 )
5384         return DPERR_INVALIDFLAGS;
5385 
5386     return dplay_cancelmsg( This, 0, DPCANCELSEND_PRIORITY, minprio, maxprio );
5387 }
5388 
5389 static const IDirectPlay2Vtbl dp2_vt =
5390 {
5391     IDirectPlay2Impl_QueryInterface,
5392     IDirectPlay2Impl_AddRef,
5393     IDirectPlay2Impl_Release,
5394     IDirectPlay2Impl_AddPlayerToGroup,
5395     IDirectPlay2Impl_Close,
5396     IDirectPlay2Impl_CreateGroup,
5397     IDirectPlay2Impl_CreatePlayer,
5398     IDirectPlay2Impl_DeletePlayerFromGroup,
5399     IDirectPlay2Impl_DestroyGroup,
5400     IDirectPlay2Impl_DestroyPlayer,
5401     IDirectPlay2Impl_EnumGroupPlayers,
5402     IDirectPlay2Impl_EnumGroups,
5403     IDirectPlay2Impl_EnumPlayers,
5404     IDirectPlay2Impl_EnumSessions,
5405     IDirectPlay2Impl_GetCaps,
5406     IDirectPlay2Impl_GetGroupData,
5407     IDirectPlay2Impl_GetGroupName,
5408     IDirectPlay2Impl_GetMessageCount,
5409     IDirectPlay2Impl_GetPlayerAddress,
5410     IDirectPlay2Impl_GetPlayerCaps,
5411     IDirectPlay2Impl_GetPlayerData,
5412     IDirectPlay2Impl_GetPlayerName,
5413     IDirectPlay2Impl_GetSessionDesc,
5414     IDirectPlay2Impl_Initialize,
5415     IDirectPlay2Impl_Open,
5416     IDirectPlay2Impl_Receive,
5417     IDirectPlay2Impl_Send,
5418     IDirectPlay2Impl_SetGroupData,
5419     IDirectPlay2Impl_SetGroupName,
5420     IDirectPlay2Impl_SetPlayerData,
5421     IDirectPlay2Impl_SetPlayerName,
5422     IDirectPlay2Impl_SetSessionDesc
5423 };
5424 
5425 static const IDirectPlay2Vtbl dp2A_vt =
5426 {
5427     IDirectPlay2AImpl_QueryInterface,
5428     IDirectPlay2AImpl_AddRef,
5429     IDirectPlay2AImpl_Release,
5430     IDirectPlay2AImpl_AddPlayerToGroup,
5431     IDirectPlay2AImpl_Close,
5432     IDirectPlay2AImpl_CreateGroup,
5433     IDirectPlay2AImpl_CreatePlayer,
5434     IDirectPlay2AImpl_DeletePlayerFromGroup,
5435     IDirectPlay2AImpl_DestroyGroup,
5436     IDirectPlay2AImpl_DestroyPlayer,
5437     IDirectPlay2AImpl_EnumGroupPlayers,
5438     IDirectPlay2AImpl_EnumGroups,
5439     IDirectPlay2AImpl_EnumPlayers,
5440     IDirectPlay2AImpl_EnumSessions,
5441     IDirectPlay2AImpl_GetCaps,
5442     IDirectPlay2AImpl_GetGroupData,
5443     IDirectPlay2AImpl_GetGroupName,
5444     IDirectPlay2AImpl_GetMessageCount,
5445     IDirectPlay2AImpl_GetPlayerAddress,
5446     IDirectPlay2AImpl_GetPlayerCaps,
5447     IDirectPlay2AImpl_GetPlayerData,
5448     IDirectPlay2AImpl_GetPlayerName,
5449     IDirectPlay2AImpl_GetSessionDesc,
5450     IDirectPlay2AImpl_Initialize,
5451     IDirectPlay2AImpl_Open,
5452     IDirectPlay2AImpl_Receive,
5453     IDirectPlay2AImpl_Send,
5454     IDirectPlay2AImpl_SetGroupData,
5455     IDirectPlay2AImpl_SetGroupName,
5456     IDirectPlay2AImpl_SetPlayerData,
5457     IDirectPlay2AImpl_SetPlayerName,
5458     IDirectPlay2AImpl_SetSessionDesc
5459 };
5460 
5461 static const IDirectPlay3Vtbl dp3_vt =
5462 {
5463     IDirectPlay3Impl_QueryInterface,
5464     IDirectPlay3Impl_AddRef,
5465     IDirectPlay3Impl_Release,
5466     IDirectPlay3Impl_AddPlayerToGroup,
5467     IDirectPlay3Impl_Close,
5468     IDirectPlay3Impl_CreateGroup,
5469     IDirectPlay3Impl_CreatePlayer,
5470     IDirectPlay3Impl_DeletePlayerFromGroup,
5471     IDirectPlay3Impl_DestroyGroup,
5472     IDirectPlay3Impl_DestroyPlayer,
5473     IDirectPlay3Impl_EnumGroupPlayers,
5474     IDirectPlay3Impl_EnumGroups,
5475     IDirectPlay3Impl_EnumPlayers,
5476     IDirectPlay3Impl_EnumSessions,
5477     IDirectPlay3Impl_GetCaps,
5478     IDirectPlay3Impl_GetGroupData,
5479     IDirectPlay3Impl_GetGroupName,
5480     IDirectPlay3Impl_GetMessageCount,
5481     IDirectPlay3Impl_GetPlayerAddress,
5482     IDirectPlay3Impl_GetPlayerCaps,
5483     IDirectPlay3Impl_GetPlayerData,
5484     IDirectPlay3Impl_GetPlayerName,
5485     IDirectPlay3Impl_GetSessionDesc,
5486     IDirectPlay3Impl_Initialize,
5487     IDirectPlay3Impl_Open,
5488     IDirectPlay3Impl_Receive,
5489     IDirectPlay3Impl_Send,
5490     IDirectPlay3Impl_SetGroupData,
5491     IDirectPlay3Impl_SetGroupName,
5492     IDirectPlay3Impl_SetPlayerData,
5493     IDirectPlay3Impl_SetPlayerName,
5494     IDirectPlay3Impl_SetSessionDesc,
5495     IDirectPlay3Impl_AddGroupToGroup,
5496     IDirectPlay3Impl_CreateGroupInGroup,
5497     IDirectPlay3Impl_DeleteGroupFromGroup,
5498     IDirectPlay3Impl_EnumConnections,
5499     IDirectPlay3Impl_EnumGroupsInGroup,
5500     IDirectPlay3Impl_GetGroupConnectionSettings,
5501     IDirectPlay3Impl_InitializeConnection,
5502     IDirectPlay3Impl_SecureOpen,
5503     IDirectPlay3Impl_SendChatMessage,
5504     IDirectPlay3Impl_SetGroupConnectionSettings,
5505     IDirectPlay3Impl_StartSession,
5506     IDirectPlay3Impl_GetGroupFlags,
5507     IDirectPlay3Impl_GetGroupParent,
5508     IDirectPlay3Impl_GetPlayerAccount,
5509     IDirectPlay3Impl_GetPlayerFlags
5510 };
5511 
5512 static const IDirectPlay3Vtbl dp3A_vt =
5513 {
5514     IDirectPlay3AImpl_QueryInterface,
5515     IDirectPlay3AImpl_AddRef,
5516     IDirectPlay3AImpl_Release,
5517     IDirectPlay3AImpl_AddPlayerToGroup,
5518     IDirectPlay3AImpl_Close,
5519     IDirectPlay3AImpl_CreateGroup,
5520     IDirectPlay3AImpl_CreatePlayer,
5521     IDirectPlay3AImpl_DeletePlayerFromGroup,
5522     IDirectPlay3AImpl_DestroyGroup,
5523     IDirectPlay3AImpl_DestroyPlayer,
5524     IDirectPlay3AImpl_EnumGroupPlayers,
5525     IDirectPlay3AImpl_EnumGroups,
5526     IDirectPlay3AImpl_EnumPlayers,
5527     IDirectPlay3AImpl_EnumSessions,
5528     IDirectPlay3AImpl_GetCaps,
5529     IDirectPlay3AImpl_GetGroupData,
5530     IDirectPlay3AImpl_GetGroupName,
5531     IDirectPlay3AImpl_GetMessageCount,
5532     IDirectPlay3AImpl_GetPlayerAddress,
5533     IDirectPlay3AImpl_GetPlayerCaps,
5534     IDirectPlay3AImpl_GetPlayerData,
5535     IDirectPlay3AImpl_GetPlayerName,
5536     IDirectPlay3AImpl_GetSessionDesc,
5537     IDirectPlay3AImpl_Initialize,
5538     IDirectPlay3AImpl_Open,
5539     IDirectPlay3AImpl_Receive,
5540     IDirectPlay3AImpl_Send,
5541     IDirectPlay3AImpl_SetGroupData,
5542     IDirectPlay3AImpl_SetGroupName,
5543     IDirectPlay3AImpl_SetPlayerData,
5544     IDirectPlay3AImpl_SetPlayerName,
5545     IDirectPlay3AImpl_SetSessionDesc,
5546     IDirectPlay3AImpl_AddGroupToGroup,
5547     IDirectPlay3AImpl_CreateGroupInGroup,
5548     IDirectPlay3AImpl_DeleteGroupFromGroup,
5549     IDirectPlay3AImpl_EnumConnections,
5550     IDirectPlay3AImpl_EnumGroupsInGroup,
5551     IDirectPlay3AImpl_GetGroupConnectionSettings,
5552     IDirectPlay3AImpl_InitializeConnection,
5553     IDirectPlay3AImpl_SecureOpen,
5554     IDirectPlay3AImpl_SendChatMessage,
5555     IDirectPlay3AImpl_SetGroupConnectionSettings,
5556     IDirectPlay3AImpl_StartSession,
5557     IDirectPlay3AImpl_GetGroupFlags,
5558     IDirectPlay3AImpl_GetGroupParent,
5559     IDirectPlay3AImpl_GetPlayerAccount,
5560     IDirectPlay3AImpl_GetPlayerFlags
5561 };
5562 
5563 static const IDirectPlay4Vtbl dp4_vt =
5564 {
5565     IDirectPlay4Impl_QueryInterface,
5566     IDirectPlay4Impl_AddRef,
5567     IDirectPlay4Impl_Release,
5568     IDirectPlay4Impl_AddPlayerToGroup,
5569     IDirectPlay4Impl_Close,
5570     IDirectPlay4Impl_CreateGroup,
5571     IDirectPlay4Impl_CreatePlayer,
5572     IDirectPlay4Impl_DeletePlayerFromGroup,
5573     IDirectPlay4Impl_DestroyGroup,
5574     IDirectPlay4Impl_DestroyPlayer,
5575     IDirectPlay4Impl_EnumGroupPlayers,
5576     IDirectPlay4Impl_EnumGroups,
5577     IDirectPlay4Impl_EnumPlayers,
5578     IDirectPlay4Impl_EnumSessions,
5579     IDirectPlay4Impl_GetCaps,
5580     IDirectPlay4Impl_GetGroupData,
5581     IDirectPlay4Impl_GetGroupName,
5582     IDirectPlay4Impl_GetMessageCount,
5583     IDirectPlay4Impl_GetPlayerAddress,
5584     IDirectPlay4Impl_GetPlayerCaps,
5585     IDirectPlay4Impl_GetPlayerData,
5586     IDirectPlay4Impl_GetPlayerName,
5587     IDirectPlay4Impl_GetSessionDesc,
5588     IDirectPlay4Impl_Initialize,
5589     IDirectPlay4Impl_Open,
5590     IDirectPlay4Impl_Receive,
5591     IDirectPlay4Impl_Send,
5592     IDirectPlay4Impl_SetGroupData,
5593     IDirectPlay4Impl_SetGroupName,
5594     IDirectPlay4Impl_SetPlayerData,
5595     IDirectPlay4Impl_SetPlayerName,
5596     IDirectPlay4Impl_SetSessionDesc,
5597     IDirectPlay4Impl_AddGroupToGroup,
5598     IDirectPlay4Impl_CreateGroupInGroup,
5599     IDirectPlay4Impl_DeleteGroupFromGroup,
5600     IDirectPlay4Impl_EnumConnections,
5601     IDirectPlay4Impl_EnumGroupsInGroup,
5602     IDirectPlay4Impl_GetGroupConnectionSettings,
5603     IDirectPlay4Impl_InitializeConnection,
5604     IDirectPlay4Impl_SecureOpen,
5605     IDirectPlay4Impl_SendChatMessage,
5606     IDirectPlay4Impl_SetGroupConnectionSettings,
5607     IDirectPlay4Impl_StartSession,
5608     IDirectPlay4Impl_GetGroupFlags,
5609     IDirectPlay4Impl_GetGroupParent,
5610     IDirectPlay4Impl_GetPlayerAccount,
5611     IDirectPlay4Impl_GetPlayerFlags,
5612     IDirectPlay4Impl_GetGroupOwner,
5613     IDirectPlay4Impl_SetGroupOwner,
5614     IDirectPlay4Impl_SendEx,
5615     IDirectPlay4Impl_GetMessageQueue,
5616     IDirectPlay4Impl_CancelMessage,
5617     IDirectPlay4Impl_CancelPriority
5618 };
5619 
5620 static const IDirectPlay4Vtbl dp4A_vt =
5621 {
5622     IDirectPlay4AImpl_QueryInterface,
5623     IDirectPlay4AImpl_AddRef,
5624     IDirectPlay4AImpl_Release,
5625     IDirectPlay4AImpl_AddPlayerToGroup,
5626     IDirectPlay4AImpl_Close,
5627     IDirectPlay4AImpl_CreateGroup,
5628     IDirectPlay4AImpl_CreatePlayer,
5629     IDirectPlay4AImpl_DeletePlayerFromGroup,
5630     IDirectPlay4AImpl_DestroyGroup,
5631     IDirectPlay4AImpl_DestroyPlayer,
5632     IDirectPlay4AImpl_EnumGroupPlayers,
5633     IDirectPlay4AImpl_EnumGroups,
5634     IDirectPlay4AImpl_EnumPlayers,
5635     IDirectPlay4AImpl_EnumSessions,
5636     IDirectPlay4AImpl_GetCaps,
5637     IDirectPlay4AImpl_GetGroupData,
5638     IDirectPlay4AImpl_GetGroupName,
5639     IDirectPlay4AImpl_GetMessageCount,
5640     IDirectPlay4AImpl_GetPlayerAddress,
5641     IDirectPlay4AImpl_GetPlayerCaps,
5642     IDirectPlay4AImpl_GetPlayerData,
5643     IDirectPlay4AImpl_GetPlayerName,
5644     IDirectPlay4AImpl_GetSessionDesc,
5645     IDirectPlay4AImpl_Initialize,
5646     IDirectPlay4AImpl_Open,
5647     IDirectPlay4AImpl_Receive,
5648     IDirectPlay4AImpl_Send,
5649     IDirectPlay4AImpl_SetGroupData,
5650     IDirectPlay4AImpl_SetGroupName,
5651     IDirectPlay4AImpl_SetPlayerData,
5652     IDirectPlay4AImpl_SetPlayerName,
5653     IDirectPlay4AImpl_SetSessionDesc,
5654     IDirectPlay4AImpl_AddGroupToGroup,
5655     IDirectPlay4AImpl_CreateGroupInGroup,
5656     IDirectPlay4AImpl_DeleteGroupFromGroup,
5657     IDirectPlay4AImpl_EnumConnections,
5658     IDirectPlay4AImpl_EnumGroupsInGroup,
5659     IDirectPlay4AImpl_GetGroupConnectionSettings,
5660     IDirectPlay4AImpl_InitializeConnection,
5661     IDirectPlay4AImpl_SecureOpen,
5662     IDirectPlay4AImpl_SendChatMessage,
5663     IDirectPlay4AImpl_SetGroupConnectionSettings,
5664     IDirectPlay4AImpl_StartSession,
5665     IDirectPlay4AImpl_GetGroupFlags,
5666     IDirectPlay4AImpl_GetGroupParent,
5667     IDirectPlay4AImpl_GetPlayerAccount,
5668     IDirectPlay4AImpl_GetPlayerFlags,
5669     IDirectPlay4AImpl_GetGroupOwner,
5670     IDirectPlay4AImpl_SetGroupOwner,
5671     IDirectPlay4AImpl_SendEx,
5672     IDirectPlay4AImpl_GetMessageQueue,
5673     IDirectPlay4AImpl_CancelMessage,
5674     IDirectPlay4AImpl_CancelPriority
5675 };
5676 
5677 HRESULT dplay_create( REFIID riid, void **ppv )
5678 {
5679     IDirectPlayImpl *obj;
5680     HRESULT hr;
5681 
5682     TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv );
5683 
5684     *ppv = NULL;
5685     obj = HeapAlloc( GetProcessHeap(), 0, sizeof( *obj ) );
5686     if ( !obj )
5687         return DPERR_OUTOFMEMORY;
5688 
5689     obj->IDirectPlay_iface.lpVtbl = &dp_vt;
5690     obj->IDirectPlay2A_iface.lpVtbl = &dp2A_vt;
5691     obj->IDirectPlay2_iface.lpVtbl = &dp2_vt;
5692     obj->IDirectPlay3A_iface.lpVtbl = &dp3A_vt;
5693     obj->IDirectPlay3_iface.lpVtbl = &dp3_vt;
5694     obj->IDirectPlay4A_iface.lpVtbl = &dp4A_vt;
5695     obj->IDirectPlay4_iface.lpVtbl = &dp4_vt;
5696     obj->numIfaces = 1;
5697     obj->ref = 0;
5698     obj->ref2A = 0;
5699     obj->ref2 = 0;
5700     obj->ref3A = 0;
5701     obj->ref3 = 0;
5702     obj->ref4A = 0;
5703     obj->ref4 = 1;
5704 
5705     InitializeCriticalSection( &obj->lock );
5706     obj->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayImpl.lock");
5707 
5708     if ( DP_CreateDirectPlay2( obj ) )
5709         hr = IDirectPlayX_QueryInterface( &obj->IDirectPlay4_iface, riid, ppv );
5710     else
5711         hr = DPERR_NOMEMORY;
5712     IDirectPlayX_Release( &obj->IDirectPlay4_iface );
5713 
5714     return hr;
5715 }
5716 
5717 
5718 HRESULT DP_GetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void **lplpData )
5719 {
5720   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5721 
5722   if( lpPlayer == NULL )
5723   {
5724     return DPERR_INVALIDPLAYER;
5725   }
5726 
5727   *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5728 
5729   return DP_OK;
5730 }
5731 
5732 HRESULT DP_SetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void *lpData )
5733 {
5734   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5735 
5736   if( lpPlayer == NULL )
5737   {
5738     return DPERR_INVALIDPLAYER;
5739   }
5740 
5741   lpPlayer->lpPData->lpSPPlayerData = lpData;
5742 
5743   return DP_OK;
5744 }
5745 
5746 /***************************************************************************
5747  *  DirectPlayEnumerateAW
5748  *
5749  *  The pointer to the structure lpContext will be filled with the
5750  *  appropriate data for each service offered by the OS. These services are
5751  *  not necessarily available on this particular machine but are defined
5752  *  as simple service providers under the "Service Providers" registry key.
5753  *  This structure is then passed to lpEnumCallback for each of the different
5754  *  services.
5755  *
5756  *  This API is useful only for applications written using DirectX3 or
5757  *  worse. It is superseded by IDirectPlay3::EnumConnections which also
5758  *  gives information on the actual connections.
5759  *
5760  * defn of a service provider:
5761  * A dynamic-link library used by DirectPlay to communicate over a network.
5762  * The service provider contains all the network-specific code required
5763  * to send and receive messages. Online services and network operators can
5764  * supply service providers to use specialized hardware, protocols, communications
5765  * media, and network resources.
5766  *
5767  */
5768 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5769                                      LPDPENUMDPCALLBACKW lpEnumCallbackW,
5770                                      LPVOID lpContext)
5771 {
5772     HKEY   hkResult;
5773     static const WCHAR searchSubKey[] = {
5774 	'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5775 	'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5776 	'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5777 	'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5778     static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5779     static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5780 
5781     DWORD  dwIndex;
5782     FILETIME filetime;
5783 
5784     char  *descriptionA = NULL;
5785     DWORD max_sizeOfDescriptionA = 0;
5786     WCHAR *descriptionW = NULL;
5787     DWORD max_sizeOfDescriptionW = 0;
5788     DWORD sizeOfSubKeyName;
5789     WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5790     LONG  ret_value;
5791     static GUID *guid_cache;
5792     static int cache_count;
5793 
5794     if (!lpEnumCallbackA && !lpEnumCallbackW)
5795     {
5796 	return DPERR_INVALIDPARAMS;
5797     }
5798 
5799     /* Need to loop over the service providers in the registry */
5800     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5801 		      0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5802     {
5803 	/* Hmmm. Does this mean that there are no service providers? */
5804 	ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5805 	return DPERR_GENERIC;
5806     }
5807 
5808     dwIndex = 0;
5809     do
5810     {
5811         sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
5812 	ret_value = RegEnumKeyW(hkResult, dwIndex, subKeyName, sizeOfSubKeyName);
5813 	dwIndex++;
5814     }
5815     while (ret_value == ERROR_SUCCESS);
5816     /* The game Swing from bug 37185 expects GUID values to persist after
5817      * the end of the enumeration. */
5818     if (cache_count < dwIndex)
5819     {
5820 	HeapFree(GetProcessHeap(), 0, guid_cache);
5821 	guid_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID) * dwIndex);
5822 	if (!guid_cache)
5823 	{
5824 	    ERR(": failed to allocate required memory.\n");
5825 	    return DPERR_EXCEPTION;
5826 	}
5827 	cache_count = dwIndex;
5828     }
5829     /* Traverse all the service providers we have available */
5830     dwIndex = 0;
5831     while (1)
5832     {
5833 	HKEY  hkServiceProvider;
5834 	WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5835 	DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5836 
5837         sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
5838 	ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5839 				  NULL, NULL, NULL, &filetime);
5840 	if (ret_value == ERROR_NO_MORE_ITEMS)
5841 	    break;
5842 	else if (ret_value != ERROR_SUCCESS)
5843 	{
5844 	    ERR(": could not enumerate on service provider key.\n");
5845 	    return DPERR_EXCEPTION;
5846 	}
5847 	TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5848 
5849 	/* Open the key for this service provider */
5850 	if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5851 	{
5852 	    ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5853 	    continue;
5854 	}
5855 
5856 	/* Get the GUID from the registry */
5857 	if (RegQueryValueExW(hkServiceProvider, guidKey,
5858 			     NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5859 	{
5860 	    ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5861 	    continue;
5862 	}
5863 	if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5864 	{
5865 	    ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5866 	    continue;
5867 	}
5868 	CLSIDFromString(guidKeyContent, &guid_cache[dwIndex]);
5869 
5870 	/* The enumeration will return FALSE if we are not to continue.
5871 	 *
5872 	 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5873 	 *       and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5874 	 *       I think that it simply means that they are in-line with DirectX 6.0
5875 	 */
5876 	if (lpEnumCallbackA)
5877 	{
5878 	    DWORD sizeOfDescription = 0;
5879 
5880 	    /* Note that this is the A case of this function, so use the A variant to get the description string */
5881 	    if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5882 				 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5883 	    {
5884 		ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5885 		continue;
5886 	    }
5887 	    if (sizeOfDescription > max_sizeOfDescriptionA)
5888 	    {
5889 		HeapFree(GetProcessHeap(), 0, descriptionA);
5890 		max_sizeOfDescriptionA = sizeOfDescription;
5891 	    }
5892 	    descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5893 	    RegQueryValueExA(hkServiceProvider, "DescriptionA",
5894 			     NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5895 
5896 	    if (!lpEnumCallbackA(&guid_cache[dwIndex], descriptionA, 6, 0, lpContext))
5897 		goto end;
5898 	}
5899 	else
5900 	{
5901 	    DWORD sizeOfDescription = 0;
5902 
5903 	    if (RegQueryValueExW(hkServiceProvider, descW,
5904 				 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5905 	    {
5906 		ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5907 		continue;
5908 	    }
5909 	    if (sizeOfDescription > max_sizeOfDescriptionW)
5910 	    {
5911 		HeapFree(GetProcessHeap(), 0, descriptionW);
5912 		max_sizeOfDescriptionW = sizeOfDescription;
5913 	    }
5914 	    descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5915 	    RegQueryValueExW(hkServiceProvider, descW,
5916 			     NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5917 
5918 	    if (!lpEnumCallbackW(&guid_cache[dwIndex], descriptionW, 6, 0, lpContext))
5919 		goto end;
5920 	}
5921 
5922       dwIndex++;
5923   }
5924 
5925  end:
5926     HeapFree(GetProcessHeap(), 0, descriptionA);
5927     HeapFree(GetProcessHeap(), 0, descriptionW);
5928 
5929     return DP_OK;
5930 }
5931 
5932 /***************************************************************************
5933  *  DirectPlayEnumerate  [DPLAYX.9]
5934  *  DirectPlayEnumerateA [DPLAYX.2]
5935  */
5936 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5937 {
5938     TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5939 
5940     return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5941 }
5942 
5943 /***************************************************************************
5944  *  DirectPlayEnumerateW [DPLAYX.3]
5945  */
5946 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5947 {
5948     TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5949 
5950     return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5951 }
5952 
5953 typedef struct tagCreateEnum
5954 {
5955   LPVOID  lpConn;
5956   LPCGUID lpGuid;
5957 } CreateEnumData, *lpCreateEnumData;
5958 
5959 /* Find and copy the matching connection for the SP guid */
5960 static BOOL CALLBACK cbDPCreateEnumConnections(
5961     LPCGUID     lpguidSP,
5962     LPVOID      lpConnection,
5963     DWORD       dwConnectionSize,
5964     LPCDPNAME   lpName,
5965     DWORD       dwFlags,
5966     LPVOID      lpContext)
5967 {
5968   lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5969 
5970   if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5971   {
5972     TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5973 
5974     lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5975                                 dwConnectionSize );
5976     CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5977 
5978     /* Found the record that we were looking for */
5979     return FALSE;
5980   }
5981 
5982   /* Haven't found what were looking for yet */
5983   return TRUE;
5984 }
5985 
5986 
5987 /***************************************************************************
5988  *  DirectPlayCreate [DPLAYX.1]
5989  *
5990  */
5991 HRESULT WINAPI DirectPlayCreate
5992 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5993 {
5994   HRESULT hr;
5995   LPDIRECTPLAY3A lpDP3A;
5996   CreateEnumData cbData;
5997 
5998   TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5999 
6000   if( pUnk != NULL )
6001   {
6002     return CLASS_E_NOAGGREGATION;
6003   }
6004 
6005   if( (lplpDP == NULL) || (lpGUID == NULL) )
6006   {
6007     return DPERR_INVALIDPARAMS;
6008   }
6009 
6010   if ( dplay_create( &IID_IDirectPlay, (void**)lplpDP ) != DP_OK )
6011     return DPERR_UNAVAILABLE;
6012 
6013   if( IsEqualGUID( &GUID_NULL, lpGUID ) )
6014   {
6015     /* The GUID_NULL means don't bind a service provider. Just return the
6016        interface as is */
6017     return DP_OK;
6018   }
6019 
6020   /* Bind the desired service provider since lpGUID is non NULL */
6021   TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
6022 
6023   /* We're going to use a DP3 interface */
6024   hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
6025                                     (LPVOID*)&lpDP3A );
6026   if( FAILED(hr) )
6027   {
6028     ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
6029     return hr;
6030   }
6031 
6032   cbData.lpConn = NULL;
6033   cbData.lpGuid = lpGUID;
6034 
6035   /* We were given a service provider, find info about it... */
6036   hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
6037                                      &cbData, DPCONNECTION_DIRECTPLAY );
6038   if( ( FAILED(hr) ) ||
6039       ( cbData.lpConn == NULL )
6040     )
6041   {
6042     ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
6043     IDirectPlayX_Release( lpDP3A );
6044     return DPERR_UNAVAILABLE;
6045   }
6046 
6047   /* Initialize the service provider */
6048   hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
6049   if( FAILED(hr) )
6050   {
6051     ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
6052     HeapFree( GetProcessHeap(), 0, cbData.lpConn );
6053     IDirectPlayX_Release( lpDP3A );
6054     return hr;
6055   }
6056 
6057   /* Release our version of the interface now that we're done with it */
6058   IDirectPlayX_Release( lpDP3A );
6059   HeapFree( GetProcessHeap(), 0, cbData.lpConn );
6060 
6061   return DP_OK;
6062 }
6063