xref: /reactos/dll/directx/wine/dplayx/dplay.c (revision 02e84521)
1 /* Direct Play 2,3,4 Implementation
2  *
3  * Copyright 1998,1999,2000,2001 - Peter Hunnisett
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #define COBJMACROS
21 #include "config.h"
22 #include "wine/port.h"
23 
24 #include <stdarg.h>
25 #include <string.h>
26 
27 #define NONAMELESSUNION
28 
29 #include "windef.h"
30 #include "winerror.h"
31 #include "winbase.h"
32 #include "winnt.h"
33 #include "winreg.h"
34 #include "winnls.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
37 
38 #include "dplayx_global.h"
39 #include "name_server.h"
40 #include "dplayx_queue.h"
41 #include "wine/dplaysp.h"
42 #include "dplay_global.h"
43 
44 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
45 
46 /* FIXME: Should this be externed? */
47 extern HRESULT DPL_CreateCompoundAddress
48 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
49   LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
50 
51 
52 /* Local function prototypes */
53 static lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid );
54 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
55 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
56                              LPVOID lpData, DWORD dwDataSize );
57 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
58 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
59                                                   DWORD dwPlayerType,
60                                                   LPCDPNAME lpName,
61                                                   DWORD dwFlags,
62                                                   LPVOID lpContext );
63 static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid );
64 
65 /* Helper methods for player/group interfaces */
66 static HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
67         DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
68 static HRESULT DP_SP_SendEx( IDirectPlayImpl *This, DWORD dwFlags, void *lpData, DWORD dwDataSize,
69         DWORD dwPriority, DWORD dwTimeout, void *lpContext, DWORD *lpdwMsgID );
70 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
71                                     LPDWORD lpdwBufSize );
72 
73 static DPID DP_GetRemoteNextObjectId(void);
74 
75 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
76 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
77                                 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
78 
79 
80 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
81 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
82                                                  we don't have to change much */
83 #define DPID_NAME_SERVER 0x19a9d65b  /* Don't ask me why */
84 
85 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
86 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
87 
88 /* Strip out all dwFlags values for CREATEPLAYER msg */
89 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
90 
91 static LONG kludgePlayerGroupId = 1000;
92 
93 
94 static inline IDirectPlayImpl *impl_from_IDirectPlay( IDirectPlay *iface )
95 {
96     return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay_iface );
97 }
98 
99 static inline IDirectPlayImpl *impl_from_IDirectPlay2( IDirectPlay2 *iface )
100 {
101     return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay2_iface );
102 }
103 
104 static inline IDirectPlayImpl *impl_from_IDirectPlay2A( IDirectPlay2A *iface )
105 {
106     return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay2A_iface );
107 }
108 
109 static inline IDirectPlayImpl *impl_from_IDirectPlay3A( IDirectPlay3A *iface )
110 {
111     return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay3A_iface );
112 }
113 
114 static inline IDirectPlayImpl *impl_from_IDirectPlay3( IDirectPlay3 *iface )
115 {
116     return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay3_iface );
117 }
118 
119 static inline IDirectPlayImpl *impl_from_IDirectPlay4A( IDirectPlay4A *iface )
120 {
121     return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4A_iface );
122 }
123 
124 static inline IDirectPlayImpl *impl_from_IDirectPlay4( IDirectPlay4 *iface )
125 {
126     return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4_iface );
127 }
128 
129 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
130 {
131   IDirectPlayImpl *This = lpDP;
132 
133   This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
134   if ( This->dp2 == NULL )
135   {
136     return FALSE;
137   }
138 
139   This->dp2->bConnectionOpen = FALSE;
140 
141   This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
142   This->dp2->dwEnumSessionLock = 0;
143 
144   This->dp2->bHostInterface = FALSE;
145 
146   DPQ_INIT(This->dp2->receiveMsgs);
147   DPQ_INIT(This->dp2->sendMsgs);
148   DPQ_INIT(This->dp2->repliesExpected);
149 
150   if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
151   {
152     /* FIXME: Memory leak */
153     return FALSE;
154   }
155 
156   /* Provide an initial session desc with nothing in it */
157   This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
158                                         HEAP_ZERO_MEMORY,
159                                         sizeof( *This->dp2->lpSessionDesc ) );
160   if( This->dp2->lpSessionDesc == NULL )
161   {
162     /* FIXME: Memory leak */
163     return FALSE;
164   }
165   This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
166 
167   /* We are emulating a dp 6 implementation */
168   This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
169 
170   This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
171                                       sizeof( *This->dp2->spData.lpCB ) );
172   This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
173   This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
174 
175   /* This is the pointer to the service provider */
176   if ( FAILED( dplaysp_create( &IID_IDirectPlaySP, (void**)&This->dp2->spData.lpISP, This ) ) )
177   {
178     /* FIXME: Memory leak */
179     return FALSE;
180   }
181 
182   /* Setup lobby provider information */
183   This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
184   This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
185                                          sizeof( *This->dp2->dplspData.lpCB ) );
186   This->dp2->dplspData.lpCB->dwSize = sizeof(  *This->dp2->dplspData.lpCB );
187 
188   if( FAILED( dplobbysp_create( &IID_IDPLobbySP, (void**)&This->dp2->dplspData.lpISP, This ) )
189     )
190   {
191     /* FIXME: Memory leak */
192     return FALSE;
193   }
194 
195   return TRUE;
196 }
197 
198 /* Definition of the global function in dplayx_queue.h. #
199  * FIXME: Would it be better to have a dplayx_queue.c for this function? */
200 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
201 {
202   HeapFree( GetProcessHeap(), 0, elem );
203 }
204 
205 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
206 {
207   IDirectPlayImpl *This = lpDP;
208 
209   if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
210   {
211     TerminateThread( This->dp2->hEnumSessionThread, 0 );
212     CloseHandle( This->dp2->hEnumSessionThread );
213   }
214 
215   /* Finish with the SP - have it shutdown */
216   if( This->dp2->spData.lpCB->ShutdownEx )
217   {
218     DPSP_SHUTDOWNDATA data;
219 
220     TRACE( "Calling SP ShutdownEx\n" );
221 
222     data.lpISP = This->dp2->spData.lpISP;
223 
224     (*This->dp2->spData.lpCB->ShutdownEx)( &data );
225   }
226   else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
227   {
228     TRACE( "Calling obsolete SP Shutdown\n" );
229     (*This->dp2->spData.lpCB->Shutdown)();
230   }
231 
232   /* Unload the SP (if it exists) */
233   if( This->dp2->hServiceProvider != 0 )
234   {
235     FreeLibrary( This->dp2->hServiceProvider );
236   }
237 
238   /* Unload the Lobby Provider (if it exists) */
239   if( This->dp2->hDPLobbyProvider != 0 )
240   {
241     FreeLibrary( This->dp2->hDPLobbyProvider );
242   }
243 
244   /* FIXME: Need to delete receive and send msgs queue contents */
245 
246   NS_DeleteSessionCache( This->dp2->lpNameServerData );
247 
248   HeapFree( GetProcessHeap(), 0, This->dp2->dplspData.lpCB);
249   HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
250 
251   IDirectPlaySP_Release( This->dp2->spData.lpISP );
252 
253   /* Delete the contents */
254   HeapFree( GetProcessHeap(), 0, This->dp2 );
255 
256   return TRUE;
257 }
258 
259 static void dplay_destroy(IDirectPlayImpl *obj)
260 {
261      DP_DestroyDirectPlay2( obj );
262      obj->lock.DebugInfo->Spare[0] = 0;
263      DeleteCriticalSection( &obj->lock );
264      HeapFree( GetProcessHeap(), 0, obj );
265 }
266 
267 static inline DPID DP_NextObjectId(void)
268 {
269   return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
270 }
271 
272 /* *lplpReply will be non NULL iff there is something to reply */
273 HRESULT DP_HandleMessage( IDirectPlayImpl *This, const void *lpcMessageBody,
274         DWORD dwMessageBodySize, const void *lpcMessageHeader, WORD wCommandId, WORD wVersion,
275         void **lplpReply, DWORD *lpdwMsgSize )
276 {
277   TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
278          This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
279          wVersion );
280 
281   switch( wCommandId )
282   {
283     /* Name server needs to handle this request */
284     case DPMSGCMD_ENUMSESSIONSREQUEST:
285       /* Reply expected */
286       NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
287       break;
288 
289     /* Name server needs to handle this request */
290     case DPMSGCMD_ENUMSESSIONSREPLY:
291       /* No reply expected */
292       NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
293                                         This->dp2->spData.dwSPHeaderSize,
294                                         lpcMessageBody,
295                                         This->dp2->lpNameServerData );
296       break;
297 
298     case DPMSGCMD_REQUESTNEWPLAYERID:
299     {
300       LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
301 
302       LPDPMSG_NEWPLAYERIDREPLY lpReply;
303 
304       *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
305 
306       *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
307 
308       FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
309              lpcMsg->dwFlags );
310 
311       /* Setup the reply */
312       lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
313                                             This->dp2->spData.dwSPHeaderSize );
314 
315       lpReply->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
316       lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
317       lpReply->envelope.wVersion   = DPMSGVER_DP6;
318 
319       lpReply->dpidNewPlayerId = DP_NextObjectId();
320 
321       TRACE( "Allocating new playerid 0x%08x from remote request\n",
322              lpReply->dpidNewPlayerId );
323       break;
324     }
325 
326     case DPMSGCMD_GETNAMETABLEREPLY:
327     case DPMSGCMD_NEWPLAYERIDREPLY:
328       DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
329       break;
330 
331     case DPMSGCMD_JUSTENVELOPE:
332       TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
333       NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
334       DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
335 
336     case DPMSGCMD_FORWARDADDPLAYER:
337       TRACE( "Sending message to self to get my addr\n" );
338       DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
339       break;
340 
341     case DPMSGCMD_FORWARDADDPLAYERNACK:
342       DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
343       break;
344 
345     default:
346       FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
347       DebugBreak();
348       break;
349   }
350 
351   /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
352 
353   return DP_OK;
354 }
355 
356 
357 static HRESULT WINAPI IDirectPlayImpl_QueryInterface( IDirectPlay *iface, REFIID riid, void **ppv )
358 {
359     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
360     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
361 }
362 
363 static ULONG WINAPI IDirectPlayImpl_AddRef( IDirectPlay *iface )
364 {
365     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
366     ULONG ref = InterlockedIncrement( &This->ref );
367 
368     TRACE( "(%p) ref=%d\n", This, ref );
369 
370     if ( ref == 1 )
371         InterlockedIncrement( &This->numIfaces );
372 
373     return ref;
374 }
375 
376 static ULONG WINAPI IDirectPlayImpl_Release( IDirectPlay *iface )
377 {
378     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
379     ULONG ref = InterlockedDecrement( &This->ref );
380 
381     TRACE( "(%p) ref=%d\n", This, ref );
382 
383     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
384         dplay_destroy( This );
385 
386     return ref;
387 }
388 
389 static HRESULT WINAPI IDirectPlayImpl_AddPlayerToGroup( IDirectPlay *iface, DPID group,
390         DPID player )
391 {
392     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
393     FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, player );
394     return E_NOTIMPL;
395 }
396 
397 static HRESULT WINAPI IDirectPlayImpl_Close( IDirectPlay *iface )
398 {
399     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
400     FIXME( "(%p): stub\n", This );
401     return E_NOTIMPL;
402 }
403 
404 static HRESULT WINAPI IDirectPlayImpl_CreatePlayer( IDirectPlay *iface, DPID *player,
405         LPSTR name, LPSTR fullname, HANDLE *event )
406 {
407     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
408     FIXME( "(%p)->(%p,%s,%s,%p): stub\n", This, player, debugstr_a( name ), debugstr_a( fullname ),
409             event );
410     return E_NOTIMPL;
411 }
412 
413 static HRESULT WINAPI IDirectPlayImpl_CreateGroup( IDirectPlay *iface, DPID *group, LPSTR name,
414         LPSTR fullname )
415 {
416     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
417     FIXME( "(%p)->(%p,%s,%s): stub\n", This, group, debugstr_a( name ), debugstr_a( fullname ) );
418     return E_NOTIMPL;
419 }
420 
421 static HRESULT WINAPI IDirectPlayImpl_DeletePlayerFromGroup( IDirectPlay *iface, DPID group,
422         DPID player )
423 {
424     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
425     FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, player );
426     return E_NOTIMPL;
427 }
428 
429 static HRESULT WINAPI IDirectPlayImpl_DestroyPlayer( IDirectPlay *iface, DPID player )
430 {
431     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
432     FIXME( "(%p)->(0x%08x): stub\n", This, player );
433     return E_NOTIMPL;
434 }
435 
436 static HRESULT WINAPI IDirectPlayImpl_DestroyGroup( IDirectPlay *iface, DPID group )
437 {
438     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
439     FIXME( "(%p)->(0x%08x): stub\n", This, group );
440     return E_NOTIMPL;
441 }
442 
443 static HRESULT WINAPI IDirectPlayImpl_EnableNewPlayers( IDirectPlay *iface, BOOL enable )
444 {
445     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
446     FIXME( "(%p)->(%d): stub\n", This, enable );
447     return E_NOTIMPL;
448 }
449 
450 static HRESULT WINAPI IDirectPlayImpl_EnumGroupPlayers( IDirectPlay *iface, DPID group,
451         LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
452 {
453     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
454     FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, group, enumplayercb, context, flags );
455     return E_NOTIMPL;
456 }
457 
458 static HRESULT WINAPI IDirectPlayImpl_EnumGroups( IDirectPlay *iface, DWORD session,
459         LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
460 {
461     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
462     FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, session, enumplayercb, context, flags );
463     return E_NOTIMPL;
464 }
465 
466 static HRESULT WINAPI IDirectPlayImpl_EnumPlayers( IDirectPlay *iface, DWORD session,
467         LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
468 {
469     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
470     FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, session, enumplayercb, context, flags );
471     return E_NOTIMPL;
472 }
473 
474 static HRESULT WINAPI IDirectPlayImpl_EnumSessions( IDirectPlay *iface, DPSESSIONDESC *sdesc,
475         DWORD timeout, LPDPENUMSESSIONSCALLBACK enumsessioncb, void *context, DWORD flags )
476 {
477     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
478     FIXME( "(%p)->(%p,%u,%p,%p,0x%08x): stub\n", This, sdesc, timeout, enumsessioncb, context,
479             flags );
480     return E_NOTIMPL;
481 }
482 
483 static HRESULT WINAPI IDirectPlayImpl_GetCaps( IDirectPlay *iface, DPCAPS *caps )
484 {
485     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
486     FIXME( "(%p)->(%p): stub\n", This, caps );
487     return E_NOTIMPL;
488 }
489 
490 static HRESULT WINAPI IDirectPlayImpl_GetMessageCount( IDirectPlay *iface, DPID player,
491         DWORD *count )
492 {
493     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
494     FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, count );
495     return E_NOTIMPL;
496 }
497 
498 static HRESULT WINAPI IDirectPlayImpl_GetPlayerCaps( IDirectPlay *iface, DPID player, DPCAPS *caps )
499 {
500     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
501     FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, caps );
502     return E_NOTIMPL;
503 }
504 
505 static HRESULT WINAPI IDirectPlayImpl_GetPlayerName( IDirectPlay *iface, DPID player, LPSTR name,
506         DWORD *size_name, LPSTR fullname, DWORD *size_fullname )
507 {
508     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
509     FIXME( "(%p)->(0x%08x,%p,%p,%p,%p): stub\n", This, player, name, size_name, fullname,
510             size_fullname );
511     return E_NOTIMPL;
512 }
513 
514 static HRESULT WINAPI IDirectPlayImpl_Initialize( IDirectPlay *iface, GUID *guid )
515 {
516     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
517     FIXME( "(%p)->(%p): stub\n", This, guid );
518     return E_NOTIMPL;
519 }
520 
521 static HRESULT WINAPI IDirectPlayImpl_Open( IDirectPlay *iface, DPSESSIONDESC *sdesc )
522 {
523     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
524     FIXME( "(%p)->(%p): stub\n", This, sdesc );
525     return E_NOTIMPL;
526 }
527 
528 static HRESULT WINAPI IDirectPlayImpl_Receive( IDirectPlay *iface, DPID *from, DPID *to,
529         DWORD flags, void *data, DWORD *size )
530 {
531     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
532     FIXME( "(%p)->(%p,%p,0x%08x,%p,%p): stub\n", This, from, to, flags, data, size );
533     return E_NOTIMPL;
534 }
535 
536 static HRESULT WINAPI IDirectPlayImpl_SaveSession( IDirectPlay *iface, LPSTR reserved )
537 {
538     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
539     FIXME( "(%p)->(%p): stub\n", This, reserved );
540     return E_NOTIMPL;
541 }
542 
543 static HRESULT WINAPI IDirectPlayImpl_Send( IDirectPlay *iface, DPID from, DPID to, DWORD flags,
544         void *data, DWORD size )
545 {
546     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
547     FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%u): stub\n", This, from, to, flags, data, size );
548     return E_NOTIMPL;
549 }
550 
551 static HRESULT WINAPI IDirectPlayImpl_SetPlayerName( IDirectPlay *iface, DPID player, LPSTR name,
552         LPSTR fullname )
553 {
554     IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
555     FIXME( "(%p)->(0x%08x,%s,%s): stub\n", This, player, debugstr_a( name ),
556             debugstr_a ( fullname ) );
557     return E_NOTIMPL;
558 }
559 
560 static const IDirectPlayVtbl dp_vt =
561 {
562     IDirectPlayImpl_QueryInterface,
563     IDirectPlayImpl_AddRef,
564     IDirectPlayImpl_Release,
565     IDirectPlayImpl_AddPlayerToGroup,
566     IDirectPlayImpl_Close,
567     IDirectPlayImpl_CreatePlayer,
568     IDirectPlayImpl_CreateGroup,
569     IDirectPlayImpl_DeletePlayerFromGroup,
570     IDirectPlayImpl_DestroyPlayer,
571     IDirectPlayImpl_DestroyGroup,
572     IDirectPlayImpl_EnableNewPlayers,
573     IDirectPlayImpl_EnumGroupPlayers,
574     IDirectPlayImpl_EnumGroups,
575     IDirectPlayImpl_EnumPlayers,
576     IDirectPlayImpl_EnumSessions,
577     IDirectPlayImpl_GetCaps,
578     IDirectPlayImpl_GetMessageCount,
579     IDirectPlayImpl_GetPlayerCaps,
580     IDirectPlayImpl_GetPlayerName,
581     IDirectPlayImpl_Initialize,
582     IDirectPlayImpl_Open,
583     IDirectPlayImpl_Receive,
584     IDirectPlayImpl_SaveSession,
585     IDirectPlayImpl_Send,
586     IDirectPlayImpl_SetPlayerName,
587 };
588 
589 
590 static HRESULT WINAPI IDirectPlay2AImpl_QueryInterface( IDirectPlay2A *iface, REFIID riid,
591         void **ppv )
592 {
593     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
594     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
595 }
596 
597 static HRESULT WINAPI IDirectPlay2Impl_QueryInterface( IDirectPlay2 *iface, REFIID riid,
598         void **ppv )
599 {
600     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
601     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
602 }
603 
604 static HRESULT WINAPI IDirectPlay3AImpl_QueryInterface( IDirectPlay3A *iface, REFIID riid,
605         void **ppv )
606 {
607     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
608     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
609 }
610 
611 static HRESULT WINAPI IDirectPlay3Impl_QueryInterface( IDirectPlay3 *iface, REFIID riid,
612         void **ppv )
613 {
614     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
615     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
616 }
617 
618 static HRESULT WINAPI IDirectPlay4AImpl_QueryInterface( IDirectPlay4A *iface, REFIID riid,
619         void **ppv )
620 {
621     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
622     return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
623 }
624 
625 static HRESULT WINAPI IDirectPlay4Impl_QueryInterface( IDirectPlay4 *iface, REFIID riid,
626         void **ppv )
627 {
628     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
629 
630     if ( IsEqualGUID( &IID_IUnknown, riid ) )
631     {
632         TRACE( "(%p)->(IID_IUnknown %p)\n", This, ppv );
633         *ppv = &This->IDirectPlay_iface;
634     }
635     else if ( IsEqualGUID( &IID_IDirectPlay, riid ) )
636     {
637         TRACE( "(%p)->(IID_IDirectPlay %p)\n", This, ppv );
638         *ppv = &This->IDirectPlay_iface;
639     }
640     else if ( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
641     {
642         TRACE( "(%p)->(IID_IDirectPlay2A %p)\n", This, ppv );
643         *ppv = &This->IDirectPlay2A_iface;
644     }
645     else if ( IsEqualGUID( &IID_IDirectPlay2, riid ) )
646     {
647         TRACE( "(%p)->(IID_IDirectPlay2 %p)\n", This, ppv );
648         *ppv = &This->IDirectPlay2_iface;
649     }
650     else if ( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
651     {
652         TRACE( "(%p)->(IID_IDirectPlay3A %p)\n", This, ppv );
653         *ppv = &This->IDirectPlay3A_iface;
654     }
655     else if ( IsEqualGUID( &IID_IDirectPlay3, riid ) )
656     {
657         TRACE( "(%p)->(IID_IDirectPlay3 %p)\n", This, ppv );
658         *ppv = &This->IDirectPlay3_iface;
659     }
660     else if ( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
661     {
662         TRACE( "(%p)->(IID_IDirectPlay4A %p)\n", This, ppv );
663         *ppv = &This->IDirectPlay4A_iface;
664     }
665     else if ( IsEqualGUID( &IID_IDirectPlay4, riid ) )
666     {
667         TRACE( "(%p)->(IID_IDirectPlay4 %p)\n", This, ppv );
668         *ppv = &This->IDirectPlay4_iface;
669     }
670     else
671     {
672         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
673         *ppv = NULL;
674         return E_NOINTERFACE;
675     }
676 
677     IUnknown_AddRef((IUnknown*)*ppv);
678     return S_OK;
679 }
680 
681 static ULONG WINAPI IDirectPlay2AImpl_AddRef( IDirectPlay2A *iface )
682 {
683     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
684     ULONG ref = InterlockedIncrement( &This->ref2A );
685 
686     TRACE( "(%p) ref2A=%d\n", This, ref );
687 
688     if ( ref == 1 )
689         InterlockedIncrement( &This->numIfaces );
690 
691     return ref;
692 }
693 
694 static ULONG WINAPI IDirectPlay2Impl_AddRef( IDirectPlay2 *iface )
695 {
696     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
697     ULONG ref = InterlockedIncrement( &This->ref2 );
698 
699     TRACE( "(%p) ref2=%d\n", This, ref );
700 
701     if ( ref == 1 )
702         InterlockedIncrement( &This->numIfaces );
703 
704     return ref;
705 }
706 
707 static ULONG WINAPI IDirectPlay3AImpl_AddRef( IDirectPlay3A *iface )
708 {
709     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
710     ULONG ref = InterlockedIncrement( &This->ref3A );
711 
712     TRACE( "(%p) ref3A=%d\n", This, ref );
713 
714     if ( ref == 1 )
715         InterlockedIncrement( &This->numIfaces );
716 
717     return ref;
718 }
719 
720 static ULONG WINAPI IDirectPlay3Impl_AddRef( IDirectPlay3 *iface )
721 {
722     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
723     ULONG ref = InterlockedIncrement( &This->ref3 );
724 
725     TRACE( "(%p) ref3=%d\n", This, ref );
726 
727     if ( ref == 1 )
728         InterlockedIncrement( &This->numIfaces );
729 
730     return ref;
731 }
732 
733 static ULONG WINAPI IDirectPlay4AImpl_AddRef(IDirectPlay4A *iface)
734 {
735     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
736     ULONG ref = InterlockedIncrement( &This->ref4A );
737 
738     TRACE( "(%p) ref4A=%d\n", This, ref );
739 
740     if ( ref == 1 )
741         InterlockedIncrement( &This->numIfaces );
742 
743     return ref;
744 }
745 
746 static ULONG WINAPI IDirectPlay4Impl_AddRef(IDirectPlay4 *iface)
747 {
748     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
749     ULONG ref = InterlockedIncrement( &This->ref4 );
750 
751     TRACE( "(%p) ref4=%d\n", This, ref );
752 
753     if ( ref == 1 )
754         InterlockedIncrement( &This->numIfaces );
755 
756     return ref;
757 }
758 
759 static ULONG WINAPI IDirectPlay2AImpl_Release( IDirectPlay2A *iface )
760 {
761     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
762     ULONG ref = InterlockedDecrement( &This->ref2A );
763 
764     TRACE( "(%p) ref2A=%d\n", This, ref );
765 
766     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
767         dplay_destroy( This );
768 
769     return ref;
770 }
771 
772 static ULONG WINAPI IDirectPlay2Impl_Release( IDirectPlay2 *iface )
773 {
774     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
775     ULONG ref = InterlockedDecrement( &This->ref2 );
776 
777     TRACE( "(%p) ref2=%d\n", This, ref );
778 
779     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
780         dplay_destroy( This );
781 
782     return ref;
783 }
784 
785 static ULONG WINAPI IDirectPlay3AImpl_Release( IDirectPlay3A *iface )
786 {
787     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
788     ULONG ref = InterlockedDecrement( &This->ref3A );
789 
790     TRACE( "(%p) ref3A=%d\n", This, ref );
791 
792     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
793         dplay_destroy( This );
794 
795     return ref;
796 }
797 
798 static ULONG WINAPI IDirectPlay3Impl_Release( IDirectPlay3 *iface )
799 {
800     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
801     ULONG ref = InterlockedDecrement( &This->ref3 );
802 
803     TRACE( "(%p) ref3=%d\n", This, ref );
804 
805     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
806         dplay_destroy( This );
807 
808     return ref;
809 }
810 
811 static ULONG WINAPI IDirectPlay4AImpl_Release(IDirectPlay4A *iface)
812 {
813     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
814     ULONG ref = InterlockedDecrement( &This->ref4A );
815 
816     TRACE( "(%p) ref4A=%d\n", This, ref );
817 
818     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
819         dplay_destroy( This );
820 
821     return ref;
822 }
823 
824 static ULONG WINAPI IDirectPlay4Impl_Release(IDirectPlay4 *iface)
825 {
826     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
827     ULONG ref = InterlockedDecrement( &This->ref4 );
828 
829     TRACE( "(%p) ref4=%d\n", This, ref );
830 
831     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
832         dplay_destroy( This );
833 
834     return ref;
835 }
836 
837 static HRESULT WINAPI IDirectPlay2AImpl_AddPlayerToGroup( IDirectPlay2A *iface, DPID group,
838         DPID player )
839 {
840     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
841     return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4A_iface, group, player );
842 }
843 
844 static HRESULT WINAPI IDirectPlay2Impl_AddPlayerToGroup( IDirectPlay2 *iface, DPID group,
845         DPID player )
846 {
847     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
848     return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
849 }
850 
851 static HRESULT WINAPI IDirectPlay3AImpl_AddPlayerToGroup( IDirectPlay3A *iface, DPID group,
852         DPID player )
853 {
854     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
855     return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
856 }
857 
858 static HRESULT WINAPI IDirectPlay3Impl_AddPlayerToGroup( IDirectPlay3 *iface, DPID group,
859         DPID player )
860 {
861     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
862     return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
863 }
864 
865 static HRESULT WINAPI IDirectPlay4AImpl_AddPlayerToGroup( IDirectPlay4A *iface, DPID group,
866         DPID player )
867 {
868     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
869     return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
870 }
871 
872 static HRESULT WINAPI IDirectPlay4Impl_AddPlayerToGroup( IDirectPlay4 *iface, DPID group,
873         DPID player )
874 {
875     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
876     lpGroupData  gdata;
877     lpPlayerList plist;
878     lpPlayerList newplist;
879 
880     TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
881 
882     if ( This->dp2->connectionInitialized == NO_PROVIDER )
883         return DPERR_UNINITIALIZED;
884 
885     /* Find the group */
886     if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
887         return DPERR_INVALIDGROUP;
888 
889     /* Find the player */
890     if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
891         return DPERR_INVALIDPLAYER;
892 
893     /* Create a player list (ie "shortcut" ) */
894     newplist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *newplist ) );
895     if ( !newplist )
896         return DPERR_CANTADDPLAYER;
897 
898     /* Add the shortcut */
899     plist->lpPData->uRef++;
900     newplist->lpPData = plist->lpPData;
901 
902     /* Add the player to the list of players for this group */
903     DPQ_INSERT(gdata->players, newplist, players);
904 
905     /* Let the SP know that we've added a player to the group */
906     if ( This->dp2->spData.lpCB->AddPlayerToGroup )
907     {
908         DPSP_ADDPLAYERTOGROUPDATA data;
909 
910         TRACE( "Calling SP AddPlayerToGroup\n" );
911 
912         data.idPlayer = player;
913         data.idGroup  = group;
914         data.lpISP    = This->dp2->spData.lpISP;
915 
916         (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
917     }
918 
919     /* Inform all other peers of the addition of player to the group. If there are
920      * no peers keep this event quiet.
921      * Also, if this event was the result of another machine sending it to us,
922      * don't bother rebroadcasting it.
923      */
924     if ( This->dp2->lpSessionDesc &&
925             ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
926     {
927         DPMSG_ADDPLAYERTOGROUP msg;
928         msg.dwType = DPSYS_ADDPLAYERTOGROUP;
929 
930         msg.dpIdGroup  = group;
931         msg.dpIdPlayer = player;
932 
933         /* FIXME: Correct to just use send effectively? */
934         /* FIXME: Should size include data w/ message or just message "header" */
935         /* FIXME: Check return code */
936         IDirectPlayX_SendEx( iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
937                 0, 0, NULL, NULL );
938     }
939 
940     return DP_OK;
941 }
942 
943 static HRESULT WINAPI IDirectPlay2AImpl_Close( IDirectPlay2A *iface )
944 {
945     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
946     return IDirectPlayX_Close( &This->IDirectPlay4A_iface );
947 }
948 
949 static HRESULT WINAPI IDirectPlay2Impl_Close( IDirectPlay2 *iface )
950 {
951     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
952     return IDirectPlayX_Close( &This->IDirectPlay4_iface );
953 }
954 
955 static HRESULT WINAPI IDirectPlay3AImpl_Close( IDirectPlay3A *iface )
956 {
957     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
958     return IDirectPlayX_Close( &This->IDirectPlay4_iface );
959 }
960 
961 static HRESULT WINAPI IDirectPlay3Impl_Close( IDirectPlay3 *iface )
962 {
963     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
964     return IDirectPlayX_Close( &This->IDirectPlay4_iface );
965 }
966 
967 static HRESULT WINAPI IDirectPlay4AImpl_Close( IDirectPlay4A *iface )
968 {
969     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
970     return IDirectPlayX_Close( &This->IDirectPlay4_iface);
971 }
972 
973 static HRESULT WINAPI IDirectPlay4Impl_Close( IDirectPlay4 *iface )
974 {
975     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
976     HRESULT hr = DP_OK;
977 
978     TRACE( "(%p)\n", This );
979 
980     /* FIXME: Need to find a new host I assume (how?) */
981     /* FIXME: Need to destroy all local groups */
982     /* FIXME: Need to migrate all remotely visible players to the new host */
983 
984     /* Invoke the SP callback to inform of session close */
985     if( This->dp2->spData.lpCB->CloseEx )
986     {
987         DPSP_CLOSEDATA data;
988 
989         TRACE( "Calling SP CloseEx\n" );
990         data.lpISP = This->dp2->spData.lpISP;
991         hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
992     }
993     else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
994     {
995         TRACE( "Calling SP Close (obsolete interface)\n" );
996         hr = (*This->dp2->spData.lpCB->Close)();
997     }
998 
999     return hr;
1000 }
1001 
1002 static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, const DPNAME *lpName,
1003         DWORD dwFlags, DPID idParent, BOOL bAnsi )
1004 {
1005   lpGroupData lpGData;
1006 
1007   /* Allocate the new space and add to end of high level group list */
1008   lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
1009 
1010   if( lpGData == NULL )
1011   {
1012     return NULL;
1013   }
1014 
1015   DPQ_INIT(lpGData->groups);
1016   DPQ_INIT(lpGData->players);
1017 
1018   /* Set the desired player ID - no sanity checking to see if it exists */
1019   lpGData->dpid = *lpid;
1020 
1021   DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
1022 
1023   /* FIXME: Should we check that the parent exists? */
1024   lpGData->parent  = idParent;
1025 
1026   /* FIXME: Should we validate the dwFlags? */
1027   lpGData->dwFlags = dwFlags;
1028 
1029   TRACE( "Created group id 0x%08x\n", *lpid );
1030 
1031   return lpGData;
1032 }
1033 
1034 /* This method assumes that all links to it are already deleted */
1035 static void DP_DeleteGroup( IDirectPlayImpl *This, DPID dpid )
1036 {
1037   lpGroupList lpGList;
1038 
1039   TRACE( "(%p)->(0x%08x)\n", This, dpid );
1040 
1041   DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
1042 
1043   if( lpGList == NULL )
1044   {
1045     ERR( "DPID 0x%08x not found\n", dpid );
1046     return;
1047   }
1048 
1049   if( --(lpGList->lpGData->uRef) )
1050   {
1051     FIXME( "Why is this not the last reference to group?\n" );
1052     DebugBreak();
1053   }
1054 
1055   /* Delete player */
1056   DP_DeleteDPNameStruct( &lpGList->lpGData->name );
1057   HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
1058 
1059   /* Remove and Delete Player List object */
1060   HeapFree( GetProcessHeap(), 0, lpGList );
1061 
1062 }
1063 
1064 static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid )
1065 {
1066   lpGroupList lpGroups;
1067 
1068   TRACE( "(%p)->(0x%08x)\n", This, dpid );
1069 
1070   if( dpid == DPID_SYSTEM_GROUP )
1071   {
1072     return This->dp2->lpSysGroup;
1073   }
1074   else
1075   {
1076     DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
1077   }
1078 
1079   if( lpGroups == NULL )
1080   {
1081     return NULL;
1082   }
1083 
1084   return lpGroups->lpGData;
1085 }
1086 
1087 static HRESULT DP_IF_CreateGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidGroup,
1088         DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
1089 {
1090   lpGroupData lpGData;
1091 
1092   TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1093          This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1094          dwFlags, bAnsi );
1095 
1096   if( This->dp2->connectionInitialized == NO_PROVIDER )
1097   {
1098     return DPERR_UNINITIALIZED;
1099   }
1100 
1101   /* If the name is not specified, we must provide one */
1102   if( DPID_UNKNOWN == *lpidGroup )
1103   {
1104     /* If we are the name server, we decide on the group ids. If not, we
1105      * must ask for one before attempting a creation.
1106      */
1107     if( This->dp2->bHostInterface )
1108     {
1109       *lpidGroup = DP_NextObjectId();
1110     }
1111     else
1112     {
1113       *lpidGroup = DP_GetRemoteNextObjectId();
1114     }
1115   }
1116 
1117   lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1118                             DPID_NOPARENT_GROUP, bAnsi );
1119 
1120   if( lpGData == NULL )
1121   {
1122     return DPERR_CANTADDPLAYER; /* yes player not group */
1123   }
1124 
1125   if( DPID_SYSTEM_GROUP == *lpidGroup )
1126   {
1127     This->dp2->lpSysGroup = lpGData;
1128     TRACE( "Inserting system group\n" );
1129   }
1130   else
1131   {
1132     /* Insert into the system group */
1133     lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1134     lpGroup->lpGData = lpGData;
1135 
1136     DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1137   }
1138 
1139   /* Something is now referencing this data */
1140   lpGData->uRef++;
1141 
1142   /* Set all the important stuff for the group */
1143   DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1144 
1145   /* FIXME: We should only create the system group if GetCaps returns
1146    *        DPCAPS_GROUPOPTIMIZED.
1147    */
1148 
1149   /* Let the SP know that we've created this group */
1150   if( This->dp2->spData.lpCB->CreateGroup )
1151   {
1152     DPSP_CREATEGROUPDATA data;
1153     DWORD dwCreateFlags = 0;
1154 
1155     TRACE( "Calling SP CreateGroup\n" );
1156 
1157     if( *lpidGroup == DPID_NOPARENT_GROUP )
1158       dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1159 
1160     if( lpMsgHdr == NULL )
1161       dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1162 
1163     if( dwFlags & DPGROUP_HIDDEN )
1164       dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1165 
1166     data.idGroup           = *lpidGroup;
1167     data.dwFlags           = dwCreateFlags;
1168     data.lpSPMessageHeader = lpMsgHdr;
1169     data.lpISP             = This->dp2->spData.lpISP;
1170 
1171     (*This->dp2->spData.lpCB->CreateGroup)( &data );
1172   }
1173 
1174   /* Inform all other peers of the creation of a new group. If there are
1175    * no peers keep this event quiet.
1176    * Also if this message was sent to us, don't rebroadcast.
1177    */
1178   if( ( lpMsgHdr == NULL ) &&
1179       This->dp2->lpSessionDesc &&
1180       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1181   {
1182     DPMSG_CREATEPLAYERORGROUP msg;
1183     msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1184 
1185     msg.dwPlayerType     = DPPLAYERTYPE_GROUP;
1186     msg.dpId             = *lpidGroup;
1187     msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1188     msg.lpData           = lpData;
1189     msg.dwDataSize       = dwDataSize;
1190     msg.dpnName          = *lpGroupName;
1191     msg.dpIdParent       = DPID_NOPARENT_GROUP;
1192     msg.dwFlags          = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1193 
1194     /* FIXME: Correct to just use send effectively? */
1195     /* FIXME: Should size include data w/ message or just message "header" */
1196     /* FIXME: Check return code */
1197     IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1198             sizeof( msg ), 0, 0, NULL, NULL );
1199   }
1200 
1201   return DP_OK;
1202 }
1203 
1204 static HRESULT WINAPI IDirectPlay2AImpl_CreateGroup( IDirectPlay2A *iface, DPID *lpidGroup,
1205         DPNAME *name, void *data, DWORD size, DWORD flags )
1206 {
1207     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1208     return IDirectPlayX_CreateGroup( &This->IDirectPlay4A_iface, lpidGroup, name, data, size,
1209             flags );
1210 }
1211 
1212 static HRESULT WINAPI IDirectPlay2Impl_CreateGroup( IDirectPlay2 *iface, DPID *lpidGroup,
1213         DPNAME *name, void *data, DWORD size, DWORD flags )
1214 {
1215     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1216     return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, lpidGroup, name, data, size,
1217             flags );
1218 }
1219 
1220 static HRESULT WINAPI IDirectPlay3AImpl_CreateGroup( IDirectPlay3A *iface, DPID *group,
1221         DPNAME *name, void *data, DWORD size, DWORD flags )
1222 {
1223     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
1224     return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, group, name, data, size,
1225             flags );
1226 }
1227 
1228 static HRESULT WINAPI IDirectPlay3Impl_CreateGroup( IDirectPlay3 *iface, DPID *lpidGroup,
1229         DPNAME *name, void *data, DWORD size, DWORD flags )
1230 {
1231     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1232     return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, lpidGroup, name, data, size,
1233             flags );
1234 }
1235 
1236 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroup( IDirectPlay4A *iface, DPID *lpidGroup,
1237         DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1238 {
1239     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1240 
1241     *lpidGroup = DPID_UNKNOWN;
1242 
1243     return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
1244             TRUE );
1245 }
1246 
1247 static HRESULT WINAPI IDirectPlay4Impl_CreateGroup( IDirectPlay4 *iface, DPID *lpidGroup,
1248         DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1249 {
1250     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1251 
1252     *lpidGroup = DPID_UNKNOWN;
1253 
1254     return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
1255             FALSE );
1256 }
1257 
1258 
1259 static void
1260 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1261                  LPVOID lpData, DWORD dwDataSize )
1262 {
1263   /* Clear out the data with this player */
1264   if( dwFlags & DPSET_LOCAL )
1265   {
1266     if ( lpGData->dwLocalDataSize != 0 )
1267     {
1268       HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1269       lpGData->lpLocalData = NULL;
1270       lpGData->dwLocalDataSize = 0;
1271     }
1272   }
1273   else
1274   {
1275     if( lpGData->dwRemoteDataSize != 0 )
1276     {
1277       HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1278       lpGData->lpRemoteData = NULL;
1279       lpGData->dwRemoteDataSize = 0;
1280     }
1281   }
1282 
1283   /* Reallocate for new data */
1284   if( lpData != NULL )
1285   {
1286     if( dwFlags & DPSET_LOCAL )
1287     {
1288       lpGData->lpLocalData     = lpData;
1289       lpGData->dwLocalDataSize = dwDataSize;
1290     }
1291     else
1292     {
1293       lpGData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
1294       CopyMemory( lpGData->lpRemoteData, lpData, dwDataSize );
1295       lpGData->dwRemoteDataSize = dwDataSize;
1296     }
1297   }
1298 
1299 }
1300 
1301 /* This function will just create the storage for the new player.  */
1302 static lpPlayerData DP_CreatePlayer( IDirectPlayImpl *This, DPID *lpid, DPNAME *lpName,
1303         DWORD dwFlags, HANDLE hEvent, BOOL bAnsi )
1304 {
1305   lpPlayerData lpPData;
1306 
1307   TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1308 
1309   /* Allocate the storage for the player and associate it with list element */
1310   lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1311   if( lpPData == NULL )
1312   {
1313     return NULL;
1314   }
1315 
1316   /* Set the desired player ID */
1317   lpPData->dpid = *lpid;
1318 
1319   DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1320 
1321   lpPData->dwFlags = dwFlags;
1322 
1323   /* If we were given an event handle, duplicate it */
1324   if( hEvent != 0 )
1325   {
1326     if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1327                           GetCurrentProcess(), &lpPData->hEvent,
1328                           0, FALSE, DUPLICATE_SAME_ACCESS )
1329       )
1330     {
1331       /* FIXME: Memory leak */
1332       ERR( "Can't duplicate player msg handle %p\n", hEvent );
1333     }
1334   }
1335 
1336   /* Initialize the SP data section */
1337   lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1338 
1339   TRACE( "Created player id 0x%08x\n", *lpid );
1340 
1341   if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1342     This->dp2->lpSessionDesc->dwCurrentPlayers++;
1343 
1344   return lpPData;
1345 }
1346 
1347 /* Delete the contents of the DPNAME struct */
1348 static void
1349 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1350 {
1351   HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1352   HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1353 }
1354 
1355 /* This method assumes that all links to it are already deleted */
1356 static void DP_DeletePlayer( IDirectPlayImpl *This, DPID dpid )
1357 {
1358   lpPlayerList lpPList;
1359 
1360   TRACE( "(%p)->(0x%08x)\n", This, dpid );
1361 
1362   DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1363 
1364   if( lpPList == NULL )
1365   {
1366     ERR( "DPID 0x%08x not found\n", dpid );
1367     return;
1368   }
1369 
1370   /* Verify that this is the last reference to the data */
1371   if( --(lpPList->lpPData->uRef) )
1372   {
1373     FIXME( "Why is this not the last reference to player?\n" );
1374     DebugBreak();
1375   }
1376 
1377   /* Delete player */
1378   DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1379 
1380   CloseHandle( lpPList->lpPData->hEvent );
1381   HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1382 
1383   /* Delete Player List object */
1384   HeapFree( GetProcessHeap(), 0, lpPList );
1385 }
1386 
1387 static lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid )
1388 {
1389   lpPlayerList lpPlayers;
1390 
1391   TRACE( "(%p)->(0x%08x)\n", This, dpid );
1392 
1393   if(This->dp2->lpSysGroup == NULL)
1394     return NULL;
1395 
1396   DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1397 
1398   return lpPlayers;
1399 }
1400 
1401 /* Basic area for Dst must already be allocated */
1402 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1403 {
1404   if( lpSrc == NULL )
1405   {
1406     ZeroMemory( lpDst, sizeof( *lpDst ) );
1407     lpDst->dwSize = sizeof( *lpDst );
1408     return TRUE;
1409   }
1410 
1411   if( lpSrc->dwSize != sizeof( *lpSrc) )
1412   {
1413     return FALSE;
1414   }
1415 
1416   /* Delete any existing pointers */
1417   HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1418   HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1419 
1420   /* Copy as required */
1421   CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1422 
1423   if( bAnsi )
1424   {
1425     if( lpSrc->u1.lpszShortNameA )
1426     {
1427         lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1428                                              strlen(lpSrc->u1.lpszShortNameA)+1 );
1429         strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1430     }
1431     if( lpSrc->u2.lpszLongNameA )
1432     {
1433         lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1434                                               strlen(lpSrc->u2.lpszLongNameA)+1 );
1435         strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1436     }
1437   }
1438   else
1439   {
1440     if( lpSrc->u1.lpszShortNameA )
1441     {
1442         lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1443                                               (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1444         strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1445     }
1446     if( lpSrc->u2.lpszLongNameA )
1447     {
1448         lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1449                                              (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1450         strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1451     }
1452   }
1453 
1454   return TRUE;
1455 }
1456 
1457 static void
1458 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1459                   LPVOID lpData, DWORD dwDataSize )
1460 {
1461   /* Clear out the data with this player */
1462   if( dwFlags & DPSET_LOCAL )
1463   {
1464     if ( lpPData->dwLocalDataSize != 0 )
1465     {
1466       HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1467       lpPData->lpLocalData = NULL;
1468       lpPData->dwLocalDataSize = 0;
1469     }
1470   }
1471   else
1472   {
1473     if( lpPData->dwRemoteDataSize != 0 )
1474     {
1475       HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1476       lpPData->lpRemoteData = NULL;
1477       lpPData->dwRemoteDataSize = 0;
1478     }
1479   }
1480 
1481   /* Reallocate for new data */
1482   if( lpData != NULL )
1483   {
1484 
1485     if( dwFlags & DPSET_LOCAL )
1486     {
1487       lpPData->lpLocalData     = lpData;
1488       lpPData->dwLocalDataSize = dwDataSize;
1489     }
1490     else
1491     {
1492       lpPData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
1493       CopyMemory( lpPData->lpRemoteData, lpData, dwDataSize );
1494       lpPData->dwRemoteDataSize = dwDataSize;
1495     }
1496   }
1497 
1498 }
1499 
1500 /* Note: lpMsgHdr is NULL for local creation, non NULL for remote creation */
1501 static HRESULT DP_IF_CreatePlayer( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidPlayer,
1502         DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags,
1503         BOOL bAnsi )
1504 {
1505   HRESULT hr = DP_OK;
1506   lpPlayerData lpPData;
1507   lpPlayerList lpPList;
1508   DWORD dwCreateFlags = 0;
1509 
1510   TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1511          This, lpidPlayer, lpPlayerName, hEvent, lpData,
1512          dwDataSize, dwFlags, bAnsi );
1513   if( This->dp2->connectionInitialized == NO_PROVIDER )
1514   {
1515     return DPERR_UNINITIALIZED;
1516   }
1517 
1518   if( dwFlags == 0 )
1519   {
1520     dwFlags = DPPLAYER_SPECTATOR;
1521   }
1522 
1523   if( lpidPlayer == NULL )
1524   {
1525     return DPERR_INVALIDPARAMS;
1526   }
1527 
1528 
1529   /* Determine the creation flags for the player. These will be passed
1530    * to the name server if requesting a player id and to the SP when
1531    * informing it of the player creation
1532    */
1533   {
1534     if( dwFlags & DPPLAYER_SERVERPLAYER )
1535     {
1536       if( *lpidPlayer == DPID_SERVERPLAYER )
1537       {
1538         /* Server player for the host interface */
1539         dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1540       }
1541       else if( *lpidPlayer == DPID_NAME_SERVER )
1542       {
1543         /* Name server - master of everything */
1544         dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1545       }
1546       else
1547       {
1548         /* Server player for a non host interface */
1549         dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1550       }
1551     }
1552 
1553     if( lpMsgHdr == NULL )
1554       dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1555   }
1556 
1557   /* Verify we know how to handle all the flags */
1558   if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1559          ( dwFlags & DPPLAYER_SPECTATOR )
1560        )
1561     )
1562   {
1563     /* Assume non fatal failure */
1564     ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1565   }
1566 
1567   /* If the name is not specified, we must provide one */
1568   if( *lpidPlayer == DPID_UNKNOWN )
1569   {
1570     /* If we are the session master, we dish out the group/player ids */
1571     if( This->dp2->bHostInterface )
1572     {
1573       *lpidPlayer = DP_NextObjectId();
1574     }
1575     else
1576     {
1577       hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1578 
1579       if( FAILED(hr) )
1580       {
1581         ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1582         return hr;
1583       }
1584     }
1585   }
1586   else
1587   {
1588     /* FIXME: Would be nice to perhaps verify that we don't already have
1589      *        this player.
1590      */
1591   }
1592 
1593   /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1594      player total */
1595   lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1596                              hEvent, bAnsi );
1597   /* Create the list object and link it in */
1598   lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1599   if( !lpPData || !lpPList )
1600   {
1601     HeapFree( GetProcessHeap(), 0, lpPData );
1602     HeapFree( GetProcessHeap(), 0, lpPList );
1603     return DPERR_CANTADDPLAYER;
1604   }
1605 
1606   lpPData->uRef = 1;
1607   lpPList->lpPData = lpPData;
1608 
1609   /* Add the player to the system group */
1610   DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1611 
1612   /* Update the information and send it to all players in the session */
1613   DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1614 
1615   /* Let the SP know that we've created this player */
1616   if( This->dp2->spData.lpCB->CreatePlayer )
1617   {
1618     DPSP_CREATEPLAYERDATA data;
1619 
1620     data.idPlayer          = *lpidPlayer;
1621     data.dwFlags           = dwCreateFlags;
1622     data.lpSPMessageHeader = lpMsgHdr;
1623     data.lpISP             = This->dp2->spData.lpISP;
1624 
1625     TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1626            *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1627 
1628     hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1629   }
1630 
1631   if( FAILED(hr) )
1632   {
1633     ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1634     return hr;
1635   }
1636 
1637   /* Now let the SP know that this player is a member of the system group */
1638   if( This->dp2->spData.lpCB->AddPlayerToGroup )
1639   {
1640     DPSP_ADDPLAYERTOGROUPDATA data;
1641 
1642     data.idPlayer = *lpidPlayer;
1643     data.idGroup  = DPID_SYSTEM_GROUP;
1644     data.lpISP    = This->dp2->spData.lpISP;
1645 
1646     TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1647 
1648     hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1649   }
1650 
1651   if( FAILED(hr) )
1652   {
1653     ERR( "Failed to add player to sys group with sp: %s\n",
1654          DPLAYX_HresultToString(hr) );
1655     return hr;
1656   }
1657 
1658 #if 1
1659   if( !This->dp2->bHostInterface )
1660   {
1661     /* Let the name server know about the creation of this player */
1662     /* FIXME: Is this only to be done for the creation of a server player or
1663      *        is this used for regular players? If only for server players, move
1664      *        this call to DP_SecureOpen(...);
1665      */
1666 #if 0
1667     TRACE( "Sending message to self to get my addr\n" );
1668     DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1669 #endif
1670 
1671     hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1672   }
1673 #else
1674   /* Inform all other peers of the creation of a new player. If there are
1675    * no peers keep this quiet.
1676    * Also, if this was a remote event, no need to rebroadcast it.
1677    */
1678   if( ( lpMsgHdr == NULL ) &&
1679       This->dp2->lpSessionDesc &&
1680       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1681   {
1682     DPMSG_CREATEPLAYERORGROUP msg;
1683     msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1684 
1685     msg.dwPlayerType     = DPPLAYERTYPE_PLAYER;
1686     msg.dpId             = *lpidPlayer;
1687     msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1688     msg.lpData           = lpData;
1689     msg.dwDataSize       = dwDataSize;
1690     msg.dpnName          = *lpPlayerName;
1691     msg.dpIdParent       = DPID_NOPARENT_GROUP;
1692     msg.dwFlags          = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1693 
1694     /* FIXME: Correct to just use send effectively? */
1695     /* FIXME: Should size include data w/ message or just message "header" */
1696     /* FIXME: Check return code */
1697     hr = IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0,
1698             &msg, sizeof( msg ), 0, 0, NULL, NULL );
1699   }
1700 #endif
1701 
1702   return hr;
1703 }
1704 
1705 static HRESULT WINAPI IDirectPlay2AImpl_CreatePlayer( IDirectPlay2A *iface, DPID *lpidPlayer,
1706         DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
1707 {
1708     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1709     return IDirectPlayX_CreatePlayer( &This->IDirectPlay4A_iface, lpidPlayer, name, event, data,
1710             size, flags );
1711 }
1712 
1713 static HRESULT WINAPI IDirectPlay2Impl_CreatePlayer( IDirectPlay2 *iface, DPID *lpidPlayer,
1714         DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
1715 {
1716     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1717     return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
1718             size, flags );
1719 }
1720 
1721 static HRESULT WINAPI IDirectPlay3AImpl_CreatePlayer( IDirectPlay3A *iface, DPID *lpidPlayer,
1722         DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
1723 {
1724     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
1725     return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
1726             size, flags );
1727 }
1728 
1729 static HRESULT WINAPI IDirectPlay3Impl_CreatePlayer( IDirectPlay3 *iface, DPID *lpidPlayer,
1730         DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
1731 {
1732     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1733     return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
1734             size, flags );
1735 }
1736 
1737 static HRESULT WINAPI IDirectPlay4AImpl_CreatePlayer( IDirectPlay4A *iface, DPID *lpidPlayer,
1738         DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1739 {
1740   IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1741 
1742   if( lpidPlayer == NULL )
1743   {
1744     return DPERR_INVALIDPARAMS;
1745   }
1746 
1747   if( dwFlags & DPPLAYER_SERVERPLAYER )
1748   {
1749     *lpidPlayer = DPID_SERVERPLAYER;
1750   }
1751   else
1752   {
1753     *lpidPlayer = DPID_UNKNOWN;
1754   }
1755 
1756   return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1757                            lpData, dwDataSize, dwFlags, TRUE );
1758 }
1759 
1760 static HRESULT WINAPI IDirectPlay4Impl_CreatePlayer( IDirectPlay4 *iface, DPID *lpidPlayer,
1761         DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1762 {
1763   IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1764 
1765   if( lpidPlayer == NULL )
1766   {
1767     return DPERR_INVALIDPARAMS;
1768   }
1769 
1770   if( dwFlags & DPPLAYER_SERVERPLAYER )
1771   {
1772     *lpidPlayer = DPID_SERVERPLAYER;
1773   }
1774   else
1775   {
1776     *lpidPlayer = DPID_UNKNOWN;
1777   }
1778 
1779   return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1780                            lpData, dwDataSize, dwFlags, FALSE );
1781 }
1782 
1783 static DPID DP_GetRemoteNextObjectId(void)
1784 {
1785   FIXME( ":stub\n" );
1786 
1787   /* Hack solution */
1788   return DP_NextObjectId();
1789 }
1790 
1791 static HRESULT WINAPI IDirectPlay2AImpl_DeletePlayerFromGroup( IDirectPlay2A *iface, DPID group,
1792         DPID player )
1793 {
1794     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1795     return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4A_iface, group, player );
1796 }
1797 
1798 static HRESULT WINAPI IDirectPlay2Impl_DeletePlayerFromGroup( IDirectPlay2 *iface, DPID group,
1799         DPID player )
1800 {
1801     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1802     return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1803 }
1804 
1805 static HRESULT WINAPI IDirectPlay3AImpl_DeletePlayerFromGroup( IDirectPlay3A *iface, DPID group,
1806         DPID player )
1807 {
1808     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
1809     return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1810 }
1811 
1812 static HRESULT WINAPI IDirectPlay3Impl_DeletePlayerFromGroup( IDirectPlay3 *iface, DPID group,
1813         DPID player )
1814 {
1815     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1816     return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1817 }
1818 
1819 static HRESULT WINAPI IDirectPlay4AImpl_DeletePlayerFromGroup( IDirectPlay4A *iface, DPID group,
1820         DPID player )
1821 {
1822     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1823     return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
1824 }
1825 
1826 static HRESULT WINAPI IDirectPlay4Impl_DeletePlayerFromGroup( IDirectPlay4 *iface, DPID group,
1827         DPID player )
1828 {
1829     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1830     HRESULT hr = DP_OK;
1831 
1832     lpGroupData  gdata;
1833     lpPlayerList plist;
1834 
1835     TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
1836 
1837     /* Find the group */
1838     if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
1839         return DPERR_INVALIDGROUP;
1840 
1841     /* Find the player */
1842     if ( DP_FindPlayer( This, player ) == NULL )
1843         return DPERR_INVALIDPLAYER;
1844 
1845     /* Remove the player shortcut from the group */
1846     DPQ_REMOVE_ENTRY( gdata->players, players, lpPData->dpid, ==, player, plist );
1847 
1848     if ( !plist )
1849         return DPERR_INVALIDPLAYER;
1850 
1851     /* One less reference */
1852     plist->lpPData->uRef--;
1853 
1854     /* Delete the Player List element */
1855     HeapFree( GetProcessHeap(), 0, plist );
1856 
1857     /* Inform the SP if they care */
1858     if ( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1859     {
1860         DPSP_REMOVEPLAYERFROMGROUPDATA data;
1861 
1862         TRACE( "Calling SP RemovePlayerFromGroup\n" );
1863         data.idPlayer = player;
1864         data.idGroup = group;
1865         data.lpISP = This->dp2->spData.lpISP;
1866         hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1867     }
1868 
1869     /* Need to send a DELETEPLAYERFROMGROUP message */
1870     FIXME( "Need to send a message\n" );
1871 
1872     return hr;
1873 }
1874 
1875 typedef struct _DPRGOPContext
1876 {
1877   IDirectPlayImpl   *This;
1878   BOOL              bAnsi;
1879   DPID              idGroup;
1880 } DPRGOPContext, *lpDPRGOPContext;
1881 
1882 static BOOL CALLBACK
1883 cbRemoveGroupOrPlayer(
1884     DPID            dpId,
1885     DWORD           dwPlayerType,
1886     LPCDPNAME       lpName,
1887     DWORD           dwFlags,
1888     LPVOID          lpContext )
1889 {
1890   lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1891 
1892   TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1893            dpId, dwPlayerType, lpCtxt->idGroup );
1894 
1895   if( dwPlayerType == DPPLAYERTYPE_GROUP )
1896   {
1897     if ( FAILED( IDirectPlayX_DeleteGroupFromGroup( &lpCtxt->This->IDirectPlay4_iface,
1898                     lpCtxt->idGroup, dpId ) ) )
1899       ERR( "Unable to delete group 0x%08x from group 0x%08x\n", dpId, lpCtxt->idGroup );
1900   }
1901   else if ( FAILED( IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface,
1902                                                         lpCtxt->idGroup, dpId ) ) )
1903       ERR( "Unable to delete player 0x%08x from grp 0x%08x\n", dpId, lpCtxt->idGroup );
1904 
1905   return TRUE; /* Continue enumeration */
1906 }
1907 
1908 static HRESULT DP_IF_DestroyGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID idGroup, BOOL bAnsi )
1909 {
1910   lpGroupData lpGData;
1911   DPRGOPContext context;
1912 
1913   FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1914          This, lpMsgHdr, idGroup, bAnsi );
1915 
1916   /* Find the group */
1917   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1918   {
1919     return DPERR_INVALIDPLAYER; /* yes player */
1920   }
1921 
1922   context.This    = This;
1923   context.bAnsi   = bAnsi;
1924   context.idGroup = idGroup;
1925 
1926   /* Remove all players that this group has */
1927   IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, idGroup, NULL, cbRemoveGroupOrPlayer,
1928           &context, 0 );
1929 
1930   /* Remove all links to groups that this group has since this is dp3 */
1931   IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, idGroup, NULL, cbRemoveGroupOrPlayer,
1932           (void*)&context, 0 );
1933 
1934   /* Remove this group from the parent group - if it has one */
1935   if( ( idGroup != DPID_SYSTEM_GROUP ) && ( lpGData->parent != DPID_SYSTEM_GROUP ) )
1936     IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, lpGData->parent, idGroup );
1937 
1938   /* Now delete this group data and list from the system group */
1939   DP_DeleteGroup( This, idGroup );
1940 
1941   /* Let the SP know that we've destroyed this group */
1942   if( This->dp2->spData.lpCB->DeleteGroup )
1943   {
1944     DPSP_DELETEGROUPDATA data;
1945 
1946     FIXME( "data.dwFlags is incorrect\n" );
1947 
1948     data.idGroup = idGroup;
1949     data.dwFlags = 0;
1950     data.lpISP   = This->dp2->spData.lpISP;
1951 
1952     (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1953   }
1954 
1955   FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1956 
1957   return DP_OK;
1958 }
1959 
1960 static HRESULT WINAPI IDirectPlay2AImpl_DestroyGroup( IDirectPlay2A *iface, DPID group )
1961 {
1962     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
1963     return IDirectPlayX_DestroyGroup( &This->IDirectPlay4A_iface, group );
1964 }
1965 
1966 static HRESULT WINAPI IDirectPlay2Impl_DestroyGroup( IDirectPlay2 *iface, DPID group )
1967 {
1968     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
1969     return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
1970 }
1971 
1972 static HRESULT WINAPI IDirectPlay3AImpl_DestroyGroup( IDirectPlay3A *iface, DPID group )
1973 {
1974     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
1975     return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
1976 }
1977 
1978 static HRESULT WINAPI IDirectPlay3Impl_DestroyGroup( IDirectPlay3 *iface, DPID group )
1979 {
1980     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
1981     return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
1982 }
1983 
1984 static HRESULT WINAPI IDirectPlay4AImpl_DestroyGroup( IDirectPlay4A *iface, DPID idGroup )
1985 {
1986     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1987     return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1988 }
1989 
1990 static HRESULT WINAPI IDirectPlay4Impl_DestroyGroup( IDirectPlay4 *iface, DPID idGroup )
1991 {
1992     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1993     return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1994 }
1995 
1996 typedef struct _DPFAGContext
1997 {
1998   IDirectPlayImpl   *This;
1999   DPID              idPlayer;
2000   BOOL              bAnsi;
2001 } DPFAGContext, *lpDPFAGContext;
2002 
2003 static HRESULT DP_IF_DestroyPlayer( IDirectPlayImpl *This, void *lpMsgHdr, DPID idPlayer,
2004         BOOL bAnsi )
2005 {
2006   DPFAGContext cbContext;
2007 
2008   FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
2009          This, lpMsgHdr, idPlayer, bAnsi );
2010 
2011   if( This->dp2->connectionInitialized == NO_PROVIDER )
2012   {
2013     return DPERR_UNINITIALIZED;
2014   }
2015 
2016   if( DP_FindPlayer( This, idPlayer ) == NULL )
2017   {
2018     return DPERR_INVALIDPLAYER;
2019   }
2020 
2021   /* FIXME: If the player is remote, we must be the host to delete this */
2022 
2023   cbContext.This     = This;
2024   cbContext.idPlayer = idPlayer;
2025   cbContext.bAnsi    = bAnsi;
2026 
2027   /* Find each group and call DeletePlayerFromGroup if the player is a
2028      member of the group */
2029   IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, NULL, cbDeletePlayerFromAllGroups, &cbContext,
2030           DPENUMGROUPS_ALL );
2031 
2032   /* Now delete player and player list from the sys group */
2033   DP_DeletePlayer( This, idPlayer );
2034 
2035   /* Let the SP know that we've destroyed this group */
2036   if( This->dp2->spData.lpCB->DeletePlayer )
2037   {
2038     DPSP_DELETEPLAYERDATA data;
2039 
2040     FIXME( "data.dwFlags is incorrect\n" );
2041 
2042     data.idPlayer = idPlayer;
2043     data.dwFlags = 0;
2044     data.lpISP   = This->dp2->spData.lpISP;
2045 
2046     (*This->dp2->spData.lpCB->DeletePlayer)( &data );
2047   }
2048 
2049   FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
2050 
2051   return DP_OK;
2052 }
2053 
2054 static BOOL CALLBACK
2055 cbDeletePlayerFromAllGroups(
2056     DPID            dpId,
2057     DWORD           dwPlayerType,
2058     LPCDPNAME       lpName,
2059     DWORD           dwFlags,
2060     LPVOID          lpContext )
2061 {
2062   lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
2063 
2064   if( dwPlayerType == DPPLAYERTYPE_GROUP )
2065   {
2066     IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, lpCtxt->idPlayer );
2067 
2068     /* Enumerate all groups in this group since this will normally only
2069      * be called for top level groups
2070      */
2071     IDirectPlayX_EnumGroupsInGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, NULL,
2072             cbDeletePlayerFromAllGroups, lpContext, DPENUMGROUPS_ALL);
2073 
2074   }
2075   else
2076   {
2077     ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
2078   }
2079 
2080   return TRUE;
2081 }
2082 
2083 static HRESULT WINAPI IDirectPlay2AImpl_DestroyPlayer( IDirectPlay2A *iface, DPID player )
2084 {
2085     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2086     return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4A_iface, player );
2087 }
2088 
2089 static HRESULT WINAPI IDirectPlay2Impl_DestroyPlayer( IDirectPlay2 *iface, DPID player )
2090 {
2091     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2092     return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
2093 }
2094 
2095 static HRESULT WINAPI IDirectPlay3AImpl_DestroyPlayer( IDirectPlay3A *iface, DPID player )
2096 {
2097     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2098     return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
2099 }
2100 
2101 static HRESULT WINAPI IDirectPlay3Impl_DestroyPlayer( IDirectPlay3 *iface, DPID player )
2102 {
2103     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2104     return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
2105 }
2106 
2107 static HRESULT WINAPI IDirectPlay4AImpl_DestroyPlayer( IDirectPlay4A *iface, DPID idPlayer )
2108 {
2109     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2110     return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
2111 }
2112 
2113 static HRESULT WINAPI IDirectPlay4Impl_DestroyPlayer( IDirectPlay4 *iface, DPID idPlayer )
2114 {
2115     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2116     return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
2117 }
2118 
2119 static HRESULT WINAPI IDirectPlay2AImpl_EnumGroupPlayers( IDirectPlay2A *iface, DPID group,
2120         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2121 {
2122     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2123     return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4A_iface, group, instance,
2124             enumplayercb, context, flags );
2125 }
2126 
2127 static HRESULT WINAPI IDirectPlay2Impl_EnumGroupPlayers( IDirectPlay2 *iface, DPID group,
2128         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2129 {
2130     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2131     return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
2132             enumplayercb, context, flags );
2133 }
2134 
2135 static HRESULT WINAPI IDirectPlay3AImpl_EnumGroupPlayers( IDirectPlay3A *iface, DPID group,
2136         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2137 {
2138     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2139     return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
2140             enumplayercb, context, flags );
2141 }
2142 
2143 static HRESULT WINAPI IDirectPlay3Impl_EnumGroupPlayers( IDirectPlay3 *iface, DPID group,
2144         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2145 {
2146     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2147     return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
2148             enumplayercb, context, flags );
2149 }
2150 
2151 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupPlayers( IDirectPlay4A *iface, DPID group,
2152         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2153 {
2154     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2155     return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance, enumplayercb,
2156             context, flags );
2157 }
2158 
2159 static HRESULT WINAPI IDirectPlay4Impl_EnumGroupPlayers( IDirectPlay4 *iface, DPID group,
2160         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2161 {
2162     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2163     lpGroupData  gdata;
2164     lpPlayerList plist;
2165 
2166     FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
2167            context, flags );
2168 
2169     if ( This->dp2->connectionInitialized == NO_PROVIDER )
2170         return DPERR_UNINITIALIZED;
2171 
2172     /* Find the group */
2173     if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
2174         return DPERR_INVALIDGROUP;
2175 
2176     if ( DPQ_IS_EMPTY( gdata->players ) )
2177         return DP_OK;
2178 
2179     /* Walk the players in this group */
2180     for( plist = DPQ_FIRST( gdata->players ); ; plist = DPQ_NEXT( plist->players ) )
2181     {
2182         /* We do not enum the name server or app server as they are of no
2183          * consequence to the end user.
2184          */
2185         if ( ( plist->lpPData->dpid != DPID_NAME_SERVER ) &&
2186                 ( plist->lpPData->dpid != DPID_SERVERPLAYER ) )
2187         {
2188             /* FIXME: Need to add stuff for flags checking */
2189             if ( !enumplayercb( plist->lpPData->dpid, DPPLAYERTYPE_PLAYER,
2190                         &plist->lpPData->name, plist->lpPData->dwFlags, context ) )
2191               /* User requested break */
2192               return DP_OK;
2193         }
2194 
2195         if ( DPQ_IS_ENDOFLIST( plist->players ) )
2196             break;
2197     }
2198     return DP_OK;
2199 }
2200 
2201 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2202 static HRESULT WINAPI IDirectPlay2AImpl_EnumGroups( IDirectPlay2A *iface, GUID *instance,
2203         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2204 {
2205     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2206     return IDirectPlayX_EnumGroups( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
2207             flags );
2208 }
2209 
2210 static HRESULT WINAPI IDirectPlay2Impl_EnumGroups( IDirectPlay2 *iface, GUID *instance,
2211         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2212 {
2213     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2214     return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2215             flags );
2216 }
2217 
2218 static HRESULT WINAPI IDirectPlay3AImpl_EnumGroups( IDirectPlay3A *iface, GUID *instance,
2219         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2220 {
2221     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2222     return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2223             flags );
2224 }
2225 
2226 static HRESULT WINAPI IDirectPlay3Impl_EnumGroups( IDirectPlay3 *iface, GUID *instance,
2227         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2228 {
2229     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2230     return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2231             flags );
2232 }
2233 
2234 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroups( IDirectPlay4A *iface, GUID *instance,
2235         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2236 {
2237     return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
2238             context, flags );
2239 }
2240 
2241 static HRESULT WINAPI IDirectPlay4Impl_EnumGroups ( IDirectPlay4 *iface, GUID *instance,
2242         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2243 {
2244     return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
2245             context, flags );
2246 }
2247 
2248 static HRESULT WINAPI IDirectPlay2AImpl_EnumPlayers( IDirectPlay2A *iface, GUID *instance,
2249         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2250 {
2251     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2252     return IDirectPlayX_EnumPlayers( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
2253             flags );
2254 }
2255 
2256 static HRESULT WINAPI IDirectPlay2Impl_EnumPlayers( IDirectPlay2 *iface, GUID *instance,
2257         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2258 {
2259     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2260     return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2261             flags );
2262 }
2263 
2264 static HRESULT WINAPI IDirectPlay3AImpl_EnumPlayers( IDirectPlay3A *iface, GUID *instance,
2265         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2266 {
2267     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2268     return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2269             flags );
2270 }
2271 
2272 static HRESULT WINAPI IDirectPlay3Impl_EnumPlayers( IDirectPlay3 *iface, GUID *instance,
2273         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2274 {
2275     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2276     return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
2277             flags );
2278 }
2279 
2280 static HRESULT WINAPI IDirectPlay4AImpl_EnumPlayers( IDirectPlay4A *iface, GUID *instance,
2281         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2282 {
2283     return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
2284             context, flags );
2285 }
2286 
2287 static HRESULT WINAPI IDirectPlay4Impl_EnumPlayers( IDirectPlay4 *iface, GUID *instance,
2288         LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2289 {
2290     return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
2291             context, flags );
2292 }
2293 
2294 /* This function should call the registered callback function that the user
2295    passed into EnumSessions for each entry available.
2296  */
2297 static void DP_InvokeEnumSessionCallbacks
2298        ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2299          LPVOID lpNSInfo,
2300          DWORD dwTimeout,
2301          LPVOID lpContext )
2302 {
2303   LPDPSESSIONDESC2 lpSessionDesc;
2304 
2305   FIXME( ": not checking for conditions\n" );
2306 
2307   /* Not sure if this should be pruning but it's convenient */
2308   NS_PruneSessionCache( lpNSInfo );
2309 
2310   NS_ResetSessionEnumeration( lpNSInfo );
2311 
2312   /* Enumerate all sessions */
2313   /* FIXME: Need to indicate ANSI */
2314   while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2315   {
2316     TRACE( "EnumSessionsCallback2 invoked\n" );
2317     if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2318     {
2319       return;
2320     }
2321   }
2322 
2323   /* Invoke one last time to indicate that there is no more to come */
2324   lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2325 }
2326 
2327 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2328 {
2329   EnumSessionAsyncCallbackData* data = lpContext;
2330   HANDLE hSuicideRequest = data->hSuicideRequest;
2331   DWORD dwTimeout = data->dwTimeout;
2332 
2333   TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2334 
2335   for( ;; )
2336   {
2337     HRESULT hr;
2338 
2339     /* Sleep up to dwTimeout waiting for request to terminate thread */
2340     if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2341     {
2342       TRACE( "Thread terminating on terminate request\n" );
2343       break;
2344     }
2345 
2346     /* Now resend the enum request */
2347     hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2348                                          data->dwEnumSessionFlags,
2349                                          data->lpSpData );
2350 
2351     if( FAILED(hr) )
2352     {
2353       ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2354       /* FIXME: Should we kill this thread? How to inform the main thread? */
2355     }
2356 
2357   }
2358 
2359   TRACE( "Thread terminating\n" );
2360 
2361   /* Clean up the thread data */
2362   CloseHandle( hSuicideRequest );
2363   HeapFree( GetProcessHeap(), 0, lpContext );
2364 
2365   /* FIXME: Need to have some notification to main app thread that this is
2366    *        dead. It would serve two purposes. 1) allow sync on termination
2367    *        so that we don't actually send something to ourselves when we
2368    *        become name server (race condition) and 2) so that if we die
2369    *        abnormally something else will be able to tell.
2370    */
2371 
2372   return 1;
2373 }
2374 
2375 static void DP_KillEnumSessionThread( IDirectPlayImpl *This )
2376 {
2377   /* Does a thread exist? If so we were doing an async enum session */
2378   if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2379   {
2380     TRACE( "Killing EnumSession thread %p\n",
2381            This->dp2->hEnumSessionThread );
2382 
2383     /* Request that the thread kill itself nicely */
2384     SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2385     CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2386 
2387     /* We no longer need to know about the thread */
2388     CloseHandle( This->dp2->hEnumSessionThread );
2389 
2390     This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2391   }
2392 }
2393 
2394 static HRESULT WINAPI IDirectPlay2AImpl_EnumSessions( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
2395         DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2396 {
2397     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2398     return IDirectPlayX_EnumSessions( &This->IDirectPlay4A_iface, sdesc, timeout, enumsessioncb,
2399             context, flags );
2400 }
2401 
2402 static HRESULT WINAPI IDirectPlay2Impl_EnumSessions( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
2403         DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2404 {
2405     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2406     return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
2407             context, flags );
2408 }
2409 
2410 static HRESULT WINAPI IDirectPlay3AImpl_EnumSessions( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
2411         DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2412 {
2413     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2414     return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
2415             context, flags );
2416 }
2417 
2418 static HRESULT WINAPI IDirectPlay3Impl_EnumSessions( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
2419         DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2420 {
2421     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2422     return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
2423             context, flags );
2424 }
2425 
2426 static HRESULT WINAPI IDirectPlay4AImpl_EnumSessions( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
2427         DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2428 {
2429     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2430     return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
2431             context, flags );
2432 }
2433 
2434 static HRESULT WINAPI IDirectPlay4Impl_EnumSessions( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
2435         DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2436 {
2437     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2438     void *connection;
2439     DWORD  size;
2440     HRESULT hr = DP_OK;
2441 
2442     TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x)\n", This, sdesc, timeout, enumsessioncb,
2443             context, flags );
2444 
2445     if ( This->dp2->connectionInitialized == NO_PROVIDER )
2446         return DPERR_UNINITIALIZED;
2447 
2448     /* Can't enumerate if the interface is already open */
2449     if ( This->dp2->bConnectionOpen )
2450         return DPERR_GENERIC;
2451 
2452     /* The loading of a lobby provider _seems_ to require a backdoor loading
2453      * of the service provider to also associate with this DP object. This is
2454      * because the app doesn't seem to have to call EnumConnections and
2455      * InitializeConnection for the SP before calling this method. As such
2456      * we'll do their dirty work for them with a quick hack so as to always
2457      * load the TCP/IP service provider.
2458      *
2459      * The correct solution would seem to involve creating a dialog box which
2460      * contains the possible SPs. These dialog boxes most likely follow SDK
2461      * examples.
2462      */
2463     if ( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2464     {
2465         WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2466 
2467         if ( !DP_BuildSPCompoundAddr( (GUID*)&DPSPGUID_TCPIP, &connection, &size ) )
2468         {
2469             ERR( "Can't build compound addr\n" );
2470             return DPERR_GENERIC;
2471         }
2472 
2473         hr = IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, 0 );
2474         if ( FAILED(hr) )
2475             return hr;
2476 
2477         HeapFree( GetProcessHeap(), 0, connection );
2478         This->dp2->bSPInitialized = TRUE;
2479     }
2480 
2481 
2482     /* Use the service provider default? */
2483     if ( !timeout )
2484     {
2485         DPCAPS caps;
2486         caps.dwSize = sizeof( caps );
2487 
2488         IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, &caps, 0 );
2489         timeout = caps.dwTimeout;
2490         if ( !timeout )
2491             timeout = DPMSG_WAIT_5_SECS; /* Provide the TCP/IP default */
2492     }
2493 
2494     if ( flags & DPENUMSESSIONS_STOPASYNC )
2495     {
2496         DP_KillEnumSessionThread( This );
2497         return hr;
2498     }
2499 
2500     if ( flags & DPENUMSESSIONS_ASYNC )
2501     {
2502         /* Enumerate everything presently in the local session cache */
2503         DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
2504                 context );
2505 
2506         if ( This->dp2->dwEnumSessionLock )
2507             return DPERR_CONNECTING;
2508 
2509         /* See if we've already created a thread to service this interface */
2510         if ( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2511         {
2512             DWORD tid;
2513             This->dp2->dwEnumSessionLock++;
2514 
2515             /* Send the first enum request inline since the user may cancel a dialog
2516              * if one is presented. Also, may also have a connecting return code.
2517              */
2518             hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags,
2519                     &This->dp2->spData );
2520 
2521             if ( SUCCEEDED(hr) )
2522             {
2523                 EnumSessionAsyncCallbackData* data = HeapAlloc( GetProcessHeap(),
2524                         HEAP_ZERO_MEMORY, sizeof( *data ) );
2525                 /* FIXME: need to kill the thread on object deletion */
2526                 data->lpSpData  = &This->dp2->spData;
2527                 data->requestGuid = sdesc->guidApplication;
2528                 data->dwEnumSessionFlags = flags;
2529                 data->dwTimeout = timeout;
2530 
2531                 This->dp2->hKillEnumSessionThreadEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
2532                 if ( !DuplicateHandle( GetCurrentProcess(), This->dp2->hKillEnumSessionThreadEvent,
2533                             GetCurrentProcess(), &data->hSuicideRequest, 0, FALSE,
2534                             DUPLICATE_SAME_ACCESS ) )
2535                     ERR( "Can't duplicate thread killing handle\n" );
2536 
2537                 TRACE( ": creating EnumSessionsRequest thread\n" );
2538                 This->dp2->hEnumSessionThread = CreateThread( NULL, 0,
2539                         DP_EnumSessionsSendAsyncRequestThread, data, 0, &tid );
2540             }
2541             This->dp2->dwEnumSessionLock--;
2542         }
2543     }
2544     else
2545     {
2546         /* Invalidate the session cache for the interface */
2547         NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2548         /* Send the broadcast for session enumeration */
2549         hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags, &This->dp2->spData );
2550         SleepEx( timeout, FALSE );
2551         DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
2552                 context );
2553     }
2554 
2555     return hr;
2556 }
2557 
2558 static HRESULT WINAPI IDirectPlay2AImpl_GetCaps( IDirectPlay2A *iface, DPCAPS *caps, DWORD flags )
2559 {
2560     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2561     return IDirectPlayX_GetCaps( &This->IDirectPlay4A_iface, caps, flags );
2562 }
2563 
2564 static HRESULT WINAPI IDirectPlay2Impl_GetCaps( IDirectPlay2 *iface, DPCAPS *caps, DWORD flags )
2565 {
2566     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2567     return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
2568 }
2569 
2570 static HRESULT WINAPI IDirectPlay3AImpl_GetCaps( IDirectPlay3A *iface, DPCAPS *caps, DWORD flags )
2571 {
2572     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2573     return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
2574 }
2575 
2576 static HRESULT WINAPI IDirectPlay3Impl_GetCaps( IDirectPlay3 *iface, DPCAPS *caps, DWORD flags )
2577 {
2578     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2579     return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
2580 }
2581 
2582 static HRESULT WINAPI IDirectPlay4AImpl_GetCaps( IDirectPlay4A *iface, DPCAPS *caps, DWORD flags )
2583 {
2584     return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
2585 }
2586 
2587 static HRESULT WINAPI IDirectPlay4Impl_GetCaps( IDirectPlay4 *iface, DPCAPS *caps, DWORD flags )
2588 {
2589     return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
2590 }
2591 
2592 static HRESULT WINAPI IDirectPlay2AImpl_GetGroupData( IDirectPlay2A *iface, DPID group, void *data,
2593         DWORD *size, DWORD flags )
2594 {
2595     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2596     return IDirectPlayX_GetGroupData( &This->IDirectPlay4A_iface, group, data, size, flags );
2597 }
2598 
2599 static HRESULT WINAPI IDirectPlay2Impl_GetGroupData( IDirectPlay2 *iface, DPID group, void *data,
2600         DWORD *size, DWORD flags )
2601 {
2602     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2603     return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2604 }
2605 
2606 static HRESULT WINAPI IDirectPlay3AImpl_GetGroupData( IDirectPlay3A *iface, DPID group, void *data,
2607         DWORD *size, DWORD flags )
2608 {
2609     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2610     return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2611 }
2612 
2613 static HRESULT WINAPI IDirectPlay3Impl_GetGroupData( IDirectPlay3 *iface, DPID group, void *data,
2614         DWORD *size, DWORD flags )
2615 {
2616     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2617     return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2618 }
2619 
2620 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupData( IDirectPlay4A *iface, DPID group,
2621         void *data, DWORD *size, DWORD flags )
2622 {
2623     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2624     return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
2625 }
2626 
2627 static HRESULT WINAPI IDirectPlay4Impl_GetGroupData( IDirectPlay4 *iface, DPID group,
2628         void *data, DWORD *size, DWORD flags )
2629 {
2630     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2631     lpGroupData gdata;
2632     DWORD bufsize;
2633     void *src;
2634 
2635     TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, group, data, size, flags );
2636 
2637     if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
2638         return DPERR_INVALIDGROUP;
2639 
2640     /* How much buffer is required? */
2641     if ( flags & DPSET_LOCAL )
2642     {
2643         bufsize = gdata->dwLocalDataSize;
2644         src = gdata->lpLocalData;
2645     }
2646     else
2647     {
2648         bufsize = gdata->dwRemoteDataSize;
2649         src = gdata->lpRemoteData;
2650     }
2651 
2652     /* Is the user requesting to know how big a buffer is required? */
2653     if ( !data || *size < bufsize )
2654     {
2655         *size = bufsize;
2656         return DPERR_BUFFERTOOSMALL;
2657     }
2658 
2659     CopyMemory( data, src, bufsize );
2660 
2661     return DP_OK;
2662 }
2663 
2664 static HRESULT DP_IF_GetGroupName( IDirectPlayImpl *This, DPID idGroup, void *lpData,
2665         DWORD *lpdwDataSize, BOOL bAnsi )
2666 {
2667   lpGroupData lpGData;
2668   LPDPNAME    lpName = lpData;
2669   DWORD       dwRequiredDataSize;
2670 
2671   FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2672           This, idGroup, lpData, lpdwDataSize, bAnsi );
2673 
2674   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2675   {
2676     return DPERR_INVALIDGROUP;
2677   }
2678 
2679   dwRequiredDataSize = lpGData->name.dwSize;
2680 
2681   if( lpGData->name.u1.lpszShortNameA )
2682   {
2683     dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2684   }
2685 
2686   if( lpGData->name.u2.lpszLongNameA )
2687   {
2688     dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2689   }
2690 
2691   if( ( lpData == NULL ) ||
2692       ( *lpdwDataSize < dwRequiredDataSize )
2693     )
2694   {
2695     *lpdwDataSize = dwRequiredDataSize;
2696     return DPERR_BUFFERTOOSMALL;
2697   }
2698 
2699   /* Copy the structure */
2700   CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2701 
2702   if( lpGData->name.u1.lpszShortNameA )
2703   {
2704     strcpy( ((char*)lpName)+lpGData->name.dwSize,
2705             lpGData->name.u1.lpszShortNameA );
2706   }
2707   else
2708   {
2709     lpName->u1.lpszShortNameA = NULL;
2710   }
2711 
2712   if( lpGData->name.u1.lpszShortNameA )
2713   {
2714     strcpy( ((char*)lpName)+lpGData->name.dwSize,
2715             lpGData->name.u2.lpszLongNameA );
2716   }
2717   else
2718   {
2719     lpName->u2.lpszLongNameA = NULL;
2720   }
2721 
2722   return DP_OK;
2723 }
2724 
2725 static HRESULT WINAPI IDirectPlay2AImpl_GetGroupName( IDirectPlay2A *iface, DPID group, void *data,
2726         DWORD *size )
2727 {
2728     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2729     return IDirectPlayX_GetGroupName( &This->IDirectPlay4A_iface, group, data, size );
2730 }
2731 
2732 static HRESULT WINAPI IDirectPlay2Impl_GetGroupName( IDirectPlay2 *iface, DPID group, void *data,
2733         DWORD *size )
2734 {
2735     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2736     return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
2737 }
2738 
2739 static HRESULT WINAPI IDirectPlay3AImpl_GetGroupName( IDirectPlay3A *iface, DPID group, void *data,
2740         DWORD *size )
2741 {
2742     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2743     return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
2744 }
2745 
2746 static HRESULT WINAPI IDirectPlay3Impl_GetGroupName( IDirectPlay3 *iface, DPID group, void *data,
2747         DWORD *size )
2748 {
2749     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2750     return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
2751 }
2752 
2753 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupName( IDirectPlay4A *iface, DPID idGroup,
2754         void *lpData, DWORD *lpdwDataSize )
2755 {
2756     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2757     return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2758 }
2759 
2760 static HRESULT WINAPI IDirectPlay4Impl_GetGroupName( IDirectPlay4 *iface, DPID idGroup,
2761         void *lpData, DWORD *lpdwDataSize )
2762 {
2763     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2764     return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2765 }
2766 
2767 static HRESULT WINAPI IDirectPlay2AImpl_GetMessageCount( IDirectPlay2A *iface, DPID player,
2768         DWORD *count )
2769 {
2770     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2771     return IDirectPlayX_GetMessageCount( &This->IDirectPlay4A_iface, player, count );
2772 }
2773 
2774 static HRESULT WINAPI IDirectPlay2Impl_GetMessageCount( IDirectPlay2 *iface, DPID player,
2775         DWORD *count )
2776 {
2777     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2778     return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
2779 }
2780 
2781 static HRESULT WINAPI IDirectPlay3AImpl_GetMessageCount( IDirectPlay3A *iface, DPID player,
2782         DWORD *count )
2783 {
2784     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2785     return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
2786 }
2787 
2788 static HRESULT WINAPI IDirectPlay3Impl_GetMessageCount( IDirectPlay3 *iface, DPID player,
2789         DWORD *count )
2790 {
2791     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2792     return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
2793 }
2794 
2795 static HRESULT WINAPI IDirectPlay4AImpl_GetMessageCount( IDirectPlay4A *iface, DPID player,
2796         DWORD *count )
2797 {
2798     return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2799 }
2800 
2801 static HRESULT WINAPI IDirectPlay4Impl_GetMessageCount( IDirectPlay4 *iface, DPID player,
2802         DWORD *count )
2803 {
2804     return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2805 }
2806 
2807 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerAddress( IDirectPlay2A *iface, DPID player,
2808         void *data, DWORD *size )
2809 {
2810     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2811     return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4A_iface, player, data, size );
2812 }
2813 
2814 static HRESULT WINAPI IDirectPlay2Impl_GetPlayerAddress( IDirectPlay2 *iface, DPID player,
2815         void *data, DWORD *size )
2816 {
2817     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2818     return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
2819 }
2820 
2821 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerAddress( IDirectPlay3A *iface, DPID player,
2822         void *data, DWORD *size )
2823 {
2824     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2825     return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
2826 }
2827 
2828 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerAddress( IDirectPlay3 *iface, DPID player,
2829         void *data, DWORD *size )
2830 {
2831     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2832     return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
2833 }
2834 
2835 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAddress( IDirectPlay4A *iface, DPID player,
2836         void *data, DWORD *size )
2837 {
2838     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2839     FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2840     return DP_OK;
2841 }
2842 
2843 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAddress( IDirectPlay4 *iface, DPID player,
2844         void *data, DWORD *size )
2845 {
2846     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2847     FIXME( "(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
2848     return DP_OK;
2849 }
2850 
2851 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerCaps( IDirectPlay2A *iface, DPID player,
2852         DPCAPS *caps, DWORD flags )
2853 {
2854     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2855     return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4A_iface, player, caps, flags );
2856 }
2857 
2858 static HRESULT WINAPI IDirectPlay2Impl_GetPlayerCaps( IDirectPlay2 *iface, DPID player,
2859         DPCAPS *caps, DWORD flags )
2860 {
2861     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2862     return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2863 }
2864 
2865 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerCaps( IDirectPlay3A *iface, DPID player,
2866         DPCAPS *caps, DWORD flags )
2867 {
2868     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2869     return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2870 }
2871 
2872 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerCaps( IDirectPlay3 *iface, DPID player,
2873         DPCAPS *caps, DWORD flags )
2874 {
2875     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2876     return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2877 }
2878 
2879 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerCaps( IDirectPlay4A *iface, DPID player,
2880         DPCAPS *caps, DWORD flags )
2881 {
2882     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2883     return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2884 }
2885 
2886 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerCaps( IDirectPlay4 *iface, DPID player,
2887         DPCAPS *caps, DWORD flags )
2888 {
2889     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2890     DPSP_GETCAPSDATA data;
2891 
2892     TRACE( "(%p)->(0x%08x,%p,0x%08x)\n", This, player, caps, flags);
2893 
2894     if ( !caps )
2895         return DPERR_INVALIDPARAMS;
2896 
2897     if ( This->dp2->connectionInitialized == NO_PROVIDER )
2898         return DPERR_UNINITIALIZED;
2899 
2900     if( caps->dwSize != sizeof(DPCAPS) )
2901         return DPERR_INVALIDPARAMS;
2902 
2903     /* Query the service provider */
2904     data.idPlayer = player;
2905     data.dwFlags = flags;
2906     data.lpCaps = caps;
2907     data.lpISP = This->dp2->spData.lpISP;
2908 
2909     return (*This->dp2->spData.lpCB->GetCaps)( &data );
2910 }
2911 
2912 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerData( IDirectPlay2A *iface, DPID player,
2913         void *data, DWORD *size, DWORD flags )
2914 {
2915     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
2916     return IDirectPlayX_GetPlayerData( &This->IDirectPlay4A_iface, player, data, size, flags );
2917 }
2918 
2919 static HRESULT WINAPI IDirectPlay2Impl_GetPlayerData( IDirectPlay2 *iface, DPID player,
2920         void *data, DWORD *size, DWORD flags )
2921 {
2922     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
2923     return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2924 }
2925 
2926 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerData( IDirectPlay3A *iface, DPID player,
2927         void *data, DWORD *size, DWORD flags )
2928 {
2929     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
2930     return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2931 }
2932 
2933 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerData( IDirectPlay3 *iface, DPID player,
2934         void *data, DWORD *size, DWORD flags )
2935 {
2936     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
2937     return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2938 }
2939 
2940 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerData( IDirectPlay4A *iface, DPID player,
2941         void *data, DWORD *size, DWORD flags )
2942 {
2943     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2944     return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
2945 }
2946 
2947 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerData( IDirectPlay4 *iface, DPID player,
2948         void *data, DWORD *size, DWORD flags )
2949 {
2950     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
2951     lpPlayerList plist;
2952     DWORD bufsize;
2953     void *src;
2954 
2955     TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, player, data, size, flags );
2956 
2957     if ( This->dp2->connectionInitialized == NO_PROVIDER )
2958         return DPERR_UNINITIALIZED;
2959 
2960     if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
2961         return DPERR_INVALIDPLAYER;
2962 
2963     if ( flags & DPSET_LOCAL )
2964     {
2965         bufsize = plist->lpPData->dwLocalDataSize;
2966         src = plist->lpPData->lpLocalData;
2967     }
2968     else
2969     {
2970         bufsize = plist->lpPData->dwRemoteDataSize;
2971         src = plist->lpPData->lpRemoteData;
2972     }
2973 
2974     /* Is the user requesting to know how big a buffer is required? */
2975     if ( !data || *size < bufsize )
2976     {
2977         *size = bufsize;
2978         return DPERR_BUFFERTOOSMALL;
2979     }
2980 
2981     CopyMemory( data, src, bufsize );
2982 
2983     return DP_OK;
2984 }
2985 
2986 static HRESULT DP_IF_GetPlayerName( IDirectPlayImpl *This, DPID idPlayer, void *lpData,
2987         DWORD *lpdwDataSize, BOOL bAnsi )
2988 {
2989   lpPlayerList lpPList;
2990   LPDPNAME    lpName = lpData;
2991   DWORD       dwRequiredDataSize;
2992 
2993   FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2994          This, idPlayer, lpData, lpdwDataSize, bAnsi );
2995 
2996   if( This->dp2->connectionInitialized == NO_PROVIDER )
2997   {
2998     return DPERR_UNINITIALIZED;
2999   }
3000 
3001   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3002   {
3003     return DPERR_INVALIDPLAYER;
3004   }
3005 
3006   dwRequiredDataSize = lpPList->lpPData->name.dwSize;
3007 
3008   if( lpPList->lpPData->name.u1.lpszShortNameA )
3009   {
3010     dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
3011   }
3012 
3013   if( lpPList->lpPData->name.u2.lpszLongNameA )
3014   {
3015     dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
3016   }
3017 
3018   if( ( lpData == NULL ) ||
3019       ( *lpdwDataSize < dwRequiredDataSize )
3020     )
3021   {
3022     *lpdwDataSize = dwRequiredDataSize;
3023     return DPERR_BUFFERTOOSMALL;
3024   }
3025 
3026   /* Copy the structure */
3027   CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
3028 
3029   if( lpPList->lpPData->name.u1.lpszShortNameA )
3030   {
3031     strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
3032             lpPList->lpPData->name.u1.lpszShortNameA );
3033   }
3034   else
3035   {
3036     lpName->u1.lpszShortNameA = NULL;
3037   }
3038 
3039   if( lpPList->lpPData->name.u1.lpszShortNameA )
3040   {
3041     strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
3042             lpPList->lpPData->name.u2.lpszLongNameA );
3043   }
3044   else
3045   {
3046     lpName->u2.lpszLongNameA = NULL;
3047   }
3048 
3049   return DP_OK;
3050 }
3051 
3052 static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerName( IDirectPlay2A *iface, DPID player,
3053         void *data, DWORD *size )
3054 {
3055     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3056     return IDirectPlayX_GetPlayerName( &This->IDirectPlay4A_iface, player, data, size );
3057 }
3058 
3059 static HRESULT WINAPI IDirectPlay2Impl_GetPlayerName( IDirectPlay2 *iface, DPID player,
3060         void *data, DWORD *size )
3061 {
3062     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3063     return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
3064 }
3065 
3066 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerName( IDirectPlay3A *iface, DPID player,
3067         void *data, DWORD *size )
3068 {
3069     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3070     return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
3071 }
3072 
3073 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerName( IDirectPlay3 *iface, DPID player,
3074         void *data, DWORD *size )
3075 {
3076     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3077     return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
3078 }
3079 
3080 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
3081         void *lpData, DWORD *lpdwDataSize )
3082 {
3083     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3084     return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
3085 }
3086 
3087 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerName( IDirectPlay4 *iface, DPID idPlayer,
3088         void *lpData, DWORD *lpdwDataSize )
3089 {
3090     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3091     return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
3092 }
3093 
3094 static HRESULT DP_GetSessionDesc( IDirectPlayImpl *This, void *lpData, DWORD *lpdwDataSize,
3095         BOOL bAnsi )
3096 {
3097   DWORD dwRequiredSize;
3098 
3099   TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
3100 
3101   if( This->dp2->connectionInitialized == NO_PROVIDER )
3102   {
3103     return DPERR_UNINITIALIZED;
3104   }
3105 
3106   if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
3107   {
3108     return DPERR_INVALIDPARAMS;
3109   }
3110 
3111   /* FIXME: Get from This->dp2->lpSessionDesc */
3112   dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
3113 
3114   if ( ( lpData == NULL ) ||
3115        ( *lpdwDataSize < dwRequiredSize )
3116      )
3117   {
3118     *lpdwDataSize = dwRequiredSize;
3119     return DPERR_BUFFERTOOSMALL;
3120   }
3121 
3122   DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
3123 
3124   return DP_OK;
3125 }
3126 
3127 static HRESULT WINAPI IDirectPlay2AImpl_GetSessionDesc( IDirectPlay2A *iface, void *data,
3128         DWORD *size )
3129 {
3130     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3131     return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4A_iface, data, size );
3132 }
3133 
3134 static HRESULT WINAPI IDirectPlay2Impl_GetSessionDesc( IDirectPlay2 *iface, void *data,
3135         DWORD *size )
3136 {
3137     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3138     return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
3139 }
3140 
3141 static HRESULT WINAPI IDirectPlay3AImpl_GetSessionDesc( IDirectPlay3A *iface, void *data,
3142         DWORD *size )
3143 {
3144     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3145     return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
3146 }
3147 
3148 static HRESULT WINAPI IDirectPlay3Impl_GetSessionDesc( IDirectPlay3 *iface, void *data,
3149         DWORD *size )
3150 {
3151     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3152     return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
3153 }
3154 
3155 static HRESULT WINAPI IDirectPlay4AImpl_GetSessionDesc( IDirectPlay4A *iface, void *lpData,
3156         DWORD *lpdwDataSize )
3157 {
3158     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3159     return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
3160 }
3161 
3162 static HRESULT WINAPI IDirectPlay4Impl_GetSessionDesc( IDirectPlay4 *iface, void *lpData,
3163         DWORD *lpdwDataSize )
3164 {
3165     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3166     return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
3167 }
3168 
3169 static HRESULT WINAPI IDirectPlay2AImpl_Initialize( IDirectPlay2A *iface, GUID *guid )
3170 {
3171     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3172     return IDirectPlayX_Initialize( &This->IDirectPlay4A_iface, guid );
3173 }
3174 
3175 static HRESULT WINAPI IDirectPlay2Impl_Initialize( IDirectPlay2 *iface, GUID *guid )
3176 {
3177     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3178     return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
3179 }
3180 
3181 static HRESULT WINAPI IDirectPlay3AImpl_Initialize( IDirectPlay3A *iface, GUID *guid )
3182 {
3183     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3184     return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
3185 }
3186 
3187 static HRESULT WINAPI IDirectPlay3Impl_Initialize( IDirectPlay3 *iface, GUID *guid )
3188 {
3189     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3190     return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
3191 }
3192 
3193 /* Intended only for COM compatibility. Always returns an error. */
3194 static HRESULT WINAPI IDirectPlay4AImpl_Initialize( IDirectPlay4A *iface, GUID *guid )
3195 {
3196     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3197     TRACE("(%p)->(%p): no-op\n", This, guid );
3198     return DPERR_ALREADYINITIALIZED;
3199 }
3200 
3201 static HRESULT WINAPI IDirectPlay4Impl_Initialize( IDirectPlay4 *iface, GUID *guid )
3202 {
3203     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3204     TRACE( "(%p)->(%p): no-op\n", This, guid );
3205     return DPERR_ALREADYINITIALIZED;
3206 }
3207 
3208 
3209 static HRESULT DP_SecureOpen( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpsd, DWORD dwFlags,
3210         const DPSECURITYDESC *lpSecurity, const DPCREDENTIALS *lpCredentials, BOOL bAnsi )
3211 {
3212   HRESULT hr = DP_OK;
3213 
3214   FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
3215          This, lpsd, dwFlags, lpSecurity, lpCredentials );
3216 
3217   if( This->dp2->connectionInitialized == NO_PROVIDER )
3218   {
3219     return DPERR_UNINITIALIZED;
3220   }
3221 
3222   if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
3223   {
3224     TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
3225     return DPERR_INVALIDPARAMS;
3226   }
3227 
3228   if( This->dp2->bConnectionOpen )
3229   {
3230     TRACE( ": rejecting already open connection.\n" );
3231     return DPERR_ALREADYINITIALIZED;
3232   }
3233 
3234   /* If we're enumerating, kill the thread */
3235   DP_KillEnumSessionThread( This );
3236 
3237   if( dwFlags & DPOPEN_CREATE )
3238   {
3239     /* Rightoo - this computer is the host and the local computer needs to be
3240        the name server so that others can join this session */
3241     NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
3242 
3243     This->dp2->bHostInterface = TRUE;
3244 
3245     hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
3246     if( FAILED( hr ) )
3247     {
3248       ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
3249       return hr;
3250     }
3251   }
3252 
3253   /* Invoke the conditional callback for the service provider */
3254   if( This->dp2->spData.lpCB->Open )
3255   {
3256     DPSP_OPENDATA data;
3257 
3258     FIXME( "Not all data fields are correct. Need new parameter\n" );
3259 
3260     data.bCreate           = (dwFlags & DPOPEN_CREATE ) != 0;
3261     data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
3262                                                         : NS_GetNSAddr( This->dp2->lpNameServerData );
3263     data.lpISP             = This->dp2->spData.lpISP;
3264     data.bReturnStatus     = (dwFlags & DPOPEN_RETURNSTATUS) != 0;
3265     data.dwOpenFlags       = dwFlags;
3266     data.dwSessionFlags    = This->dp2->lpSessionDesc->dwFlags;
3267 
3268     hr = (*This->dp2->spData.lpCB->Open)(&data);
3269     if( FAILED( hr ) )
3270     {
3271       ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
3272       return hr;
3273     }
3274   }
3275 
3276   {
3277     /* Create the system group of which everything is a part of */
3278     DPID systemGroup = DPID_SYSTEM_GROUP;
3279 
3280     hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
3281                             NULL, 0, 0, TRUE );
3282 
3283   }
3284 
3285   if( dwFlags & DPOPEN_JOIN )
3286   {
3287     DPID dpidServerId = DPID_UNKNOWN;
3288 
3289     /* Create the server player for this interface. This way we can receive
3290      * messages for this session.
3291      */
3292     /* FIXME: I suppose that we should be setting an event for a receive
3293      *        type of thing. That way the messaging thread could know to wake
3294      *        up. DPlay would then trigger the hEvent for the player the
3295      *        message is directed to.
3296      */
3297     hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
3298                              0,
3299                              DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
3300 
3301   }
3302   else if( dwFlags & DPOPEN_CREATE )
3303   {
3304     DPID dpidNameServerId = DPID_NAME_SERVER;
3305 
3306     hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
3307                              0, DPPLAYER_SERVERPLAYER, bAnsi );
3308   }
3309 
3310   if( FAILED(hr) )
3311   {
3312     ERR( "Couldn't create name server/system player: %s\n",
3313          DPLAYX_HresultToString(hr) );
3314   }
3315 
3316   return hr;
3317 }
3318 
3319 static HRESULT WINAPI IDirectPlay2AImpl_Open( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
3320         DWORD flags )
3321 {
3322     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3323     return IDirectPlayX_Open( &This->IDirectPlay4A_iface, sdesc, flags );
3324 }
3325 
3326 static HRESULT WINAPI IDirectPlay2Impl_Open( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
3327         DWORD flags )
3328 {
3329     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3330     return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
3331 }
3332 
3333 static HRESULT WINAPI IDirectPlay3AImpl_Open( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
3334         DWORD flags )
3335 {
3336     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3337     return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
3338 }
3339 
3340 static HRESULT WINAPI IDirectPlay3Impl_Open( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
3341         DWORD flags )
3342 {
3343     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3344     return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
3345 }
3346 
3347 static HRESULT WINAPI IDirectPlay4AImpl_Open( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
3348         DWORD flags )
3349 {
3350     return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
3351 }
3352 
3353 static HRESULT WINAPI IDirectPlay4Impl_Open( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
3354         DWORD flags )
3355 {
3356     return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
3357 }
3358 
3359 static HRESULT DP_IF_Receive( IDirectPlayImpl *This, DPID *lpidFrom, DPID *lpidTo, DWORD dwFlags,
3360         void *lpData, DWORD *lpdwDataSize, BOOL bAnsi )
3361 {
3362   LPDPMSG lpMsg = NULL;
3363 
3364   FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
3365          This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
3366 
3367   if( This->dp2->connectionInitialized == NO_PROVIDER )
3368   {
3369     return DPERR_UNINITIALIZED;
3370   }
3371 
3372   if( dwFlags == 0 )
3373   {
3374     dwFlags = DPRECEIVE_ALL;
3375   }
3376 
3377   /* If the lpData is NULL, we must be peeking the message */
3378   if(  ( lpData == NULL ) &&
3379       !( dwFlags & DPRECEIVE_PEEK )
3380     )
3381   {
3382     return DPERR_INVALIDPARAMS;
3383   }
3384 
3385   if( dwFlags & DPRECEIVE_ALL )
3386   {
3387     lpMsg = This->dp2->receiveMsgs.lpQHFirst;
3388 
3389     if( !( dwFlags & DPRECEIVE_PEEK ) )
3390     {
3391       FIXME( "Remove from queue\n" );
3392     }
3393   }
3394   else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
3395            ( dwFlags & DPRECEIVE_FROMPLAYER )
3396          )
3397   {
3398     FIXME( "Find matching message 0x%08x\n", dwFlags );
3399   }
3400   else
3401   {
3402     ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
3403   }
3404 
3405   if( lpMsg == NULL )
3406   {
3407     return DPERR_NOMESSAGES;
3408   }
3409 
3410   /* Copy into the provided buffer */
3411   if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
3412 
3413   return DP_OK;
3414 }
3415 
3416 static HRESULT WINAPI IDirectPlay2AImpl_Receive( IDirectPlay2A *iface, DPID *from, DPID *to,
3417         DWORD flags, void *data, DWORD *size )
3418 {
3419     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3420     return IDirectPlayX_Receive( &This->IDirectPlay4A_iface, from, to, flags, data, size );
3421 }
3422 
3423 static HRESULT WINAPI IDirectPlay2Impl_Receive( IDirectPlay2 *iface, DPID *from, DPID *to,
3424         DWORD flags, void *data, DWORD *size )
3425 {
3426     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3427     return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
3428 }
3429 
3430 static HRESULT WINAPI IDirectPlay3AImpl_Receive( IDirectPlay3A *iface, DPID *from, DPID *to,
3431         DWORD flags, void *data, DWORD *size )
3432 {
3433     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3434     return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
3435 }
3436 
3437 static HRESULT WINAPI IDirectPlay3Impl_Receive( IDirectPlay3 *iface, DPID *from, DPID *to,
3438         DWORD flags, void *data, DWORD *size )
3439 {
3440     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3441     return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
3442 }
3443 
3444 static HRESULT WINAPI IDirectPlay4AImpl_Receive( IDirectPlay4A *iface, DPID *lpidFrom,
3445         DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
3446 {
3447     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3448     return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, TRUE );
3449 }
3450 
3451 static HRESULT WINAPI IDirectPlay4Impl_Receive( IDirectPlay4 *iface, DPID *lpidFrom,
3452         DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
3453 {
3454     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3455     return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, FALSE );
3456 }
3457 
3458 static HRESULT WINAPI IDirectPlay2AImpl_Send( IDirectPlay2A *iface, DPID from, DPID to,
3459         DWORD flags, void *data, DWORD size )
3460 {
3461     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3462     return IDirectPlayX_Send( &This->IDirectPlay4A_iface, from, to, flags, data, size );
3463 }
3464 
3465 static HRESULT WINAPI IDirectPlay2Impl_Send( IDirectPlay2 *iface, DPID from, DPID to,
3466         DWORD flags, void *data, DWORD size )
3467 {
3468     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3469     return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
3470 }
3471 
3472 static HRESULT WINAPI IDirectPlay3AImpl_Send( IDirectPlay3A *iface, DPID from, DPID to,
3473         DWORD flags, void *data, DWORD size )
3474 {
3475     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3476     return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
3477 }
3478 
3479 static HRESULT WINAPI IDirectPlay3Impl_Send( IDirectPlay3 *iface, DPID from, DPID to,
3480         DWORD flags, void *data, DWORD size )
3481 {
3482     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3483     return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
3484 }
3485 
3486 static HRESULT WINAPI IDirectPlay4AImpl_Send( IDirectPlay4A *iface, DPID from, DPID to,
3487         DWORD flags, void *data, DWORD size )
3488 {
3489     return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
3490 }
3491 
3492 static HRESULT WINAPI IDirectPlay4Impl_Send( IDirectPlay4 *iface, DPID from, DPID to,
3493         DWORD flags, void *data, DWORD size )
3494 {
3495     return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
3496 }
3497 
3498 static HRESULT WINAPI IDirectPlay2AImpl_SetGroupData( IDirectPlay2A *iface, DPID group, void *data,
3499         DWORD size, DWORD flags )
3500 {
3501     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3502     return IDirectPlayX_SetGroupData( &This->IDirectPlay4A_iface, group, data, size, flags );
3503 }
3504 
3505 static HRESULT WINAPI IDirectPlay2Impl_SetGroupData( IDirectPlay2 *iface, DPID group, void *data,
3506         DWORD size, DWORD flags )
3507 {
3508     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3509     return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
3510 }
3511 
3512 static HRESULT WINAPI IDirectPlay3AImpl_SetGroupData( IDirectPlay3A *iface, DPID group, void *data,
3513         DWORD size, DWORD flags )
3514 {
3515     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3516     return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
3517 }
3518 
3519 static HRESULT WINAPI IDirectPlay3Impl_SetGroupData( IDirectPlay3 *iface, DPID group, void *data,
3520         DWORD size, DWORD flags )
3521 {
3522     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3523     return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
3524 }
3525 
3526 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupData( IDirectPlay4A *iface, DPID group, void *data,
3527         DWORD size, DWORD flags )
3528 {
3529     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3530     return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
3531 }
3532 
3533 static HRESULT WINAPI IDirectPlay4Impl_SetGroupData( IDirectPlay4 *iface, DPID group, void *data,
3534         DWORD size, DWORD flags )
3535 {
3536     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3537     lpGroupData gdata;
3538 
3539     TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, group, data, size, flags );
3540 
3541     /* Parameter check */
3542     if ( !data && size )
3543         return DPERR_INVALIDPARAMS;
3544 
3545     /* Find the pointer to the data for this player */
3546     if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
3547         return DPERR_INVALIDOBJECT;
3548 
3549     if ( !(flags & DPSET_LOCAL) )
3550     {
3551         FIXME( "Was this group created by this interface?\n" );
3552         /* FIXME: If this is a remote update need to allow it but not
3553          *        send a message.
3554          */
3555     }
3556 
3557     DP_SetGroupData( gdata, flags, data, size );
3558 
3559     /* FIXME: Only send a message if this group is local to the session otherwise
3560      * it will have been rejected above
3561      */
3562     if ( !(flags & DPSET_LOCAL) )
3563         FIXME( "Send msg?\n" );
3564 
3565     return DP_OK;
3566 }
3567 
3568 static HRESULT DP_IF_SetGroupName( IDirectPlayImpl *This, DPID idGroup, DPNAME *lpGroupName,
3569         DWORD dwFlags, BOOL bAnsi )
3570 {
3571   lpGroupData lpGData;
3572 
3573   TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3574          lpGroupName, dwFlags, bAnsi );
3575 
3576   if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3577   {
3578     return DPERR_INVALIDGROUP;
3579   }
3580 
3581   DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3582 
3583   /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3584   FIXME( "Message not sent and dwFlags ignored\n" );
3585 
3586   return DP_OK;
3587 }
3588 
3589 static HRESULT WINAPI IDirectPlay2AImpl_SetGroupName( IDirectPlay2A *iface, DPID group,
3590         DPNAME *name, DWORD flags )
3591 {
3592     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3593     return IDirectPlayX_SetGroupName( &This->IDirectPlay4A_iface, group, name, flags );
3594 }
3595 
3596 static HRESULT WINAPI IDirectPlay2Impl_SetGroupName( IDirectPlay2 *iface, DPID group,
3597         DPNAME *name, DWORD flags )
3598 {
3599     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3600     return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
3601 }
3602 
3603 static HRESULT WINAPI IDirectPlay3AImpl_SetGroupName( IDirectPlay3A *iface, DPID group,
3604         DPNAME *name, DWORD flags )
3605 {
3606     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3607     return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
3608 }
3609 
3610 static HRESULT WINAPI IDirectPlay3Impl_SetGroupName( IDirectPlay3 *iface, DPID group,
3611         DPNAME *name, DWORD flags )
3612 {
3613     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3614     return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
3615 }
3616 
3617 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupName( IDirectPlay4A *iface, DPID idGroup,
3618         DPNAME *lpGroupName, DWORD dwFlags )
3619 {
3620     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3621     return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3622 }
3623 
3624 static HRESULT WINAPI IDirectPlay4Impl_SetGroupName( IDirectPlay4 *iface, DPID idGroup,
3625         DPNAME *lpGroupName, DWORD dwFlags )
3626 {
3627     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3628     return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3629 }
3630 
3631 static HRESULT WINAPI IDirectPlay2AImpl_SetPlayerData( IDirectPlay2A *iface, DPID player,
3632         void *data, DWORD size, DWORD flags )
3633 {
3634     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3635     return IDirectPlayX_SetPlayerData( &This->IDirectPlay4A_iface, player, data, size, flags );
3636 }
3637 
3638 static HRESULT WINAPI IDirectPlay2Impl_SetPlayerData( IDirectPlay2 *iface, DPID player,
3639         void *data, DWORD size, DWORD flags )
3640 {
3641     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3642     return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
3643 }
3644 
3645 static HRESULT WINAPI IDirectPlay3AImpl_SetPlayerData( IDirectPlay3A *iface, DPID player,
3646         void *data, DWORD size, DWORD flags )
3647 {
3648     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3649     return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
3650 }
3651 
3652 static HRESULT WINAPI IDirectPlay3Impl_SetPlayerData( IDirectPlay3 *iface, DPID player,
3653         void *data, DWORD size, DWORD flags )
3654 {
3655     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3656     return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
3657 }
3658 
3659 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerData( IDirectPlay4A *iface, DPID player,
3660         void *data, DWORD size, DWORD flags )
3661 {
3662     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3663     return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
3664 }
3665 
3666 static HRESULT WINAPI IDirectPlay4Impl_SetPlayerData( IDirectPlay4 *iface, DPID player,
3667         void *data, DWORD size, DWORD flags )
3668 {
3669     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3670     lpPlayerList plist;
3671 
3672     TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, player, data, size, flags );
3673 
3674     if ( This->dp2->connectionInitialized == NO_PROVIDER )
3675         return DPERR_UNINITIALIZED;
3676 
3677     /* Parameter check */
3678     if ( !data && size )
3679         return DPERR_INVALIDPARAMS;
3680 
3681     /* Find the pointer to the data for this player */
3682     if ( (plist = DP_FindPlayer( This, player )) == NULL )
3683         return DPERR_INVALIDPLAYER;
3684 
3685     if ( !(flags & DPSET_LOCAL) )
3686     {
3687         FIXME( "Was this group created by this interface?\n" );
3688         /* FIXME: If this is a remote update need to allow it but not
3689          *        send a message.
3690          */
3691     }
3692 
3693     DP_SetPlayerData( plist->lpPData, flags, data, size );
3694 
3695     if ( !(flags & DPSET_LOCAL) )
3696         FIXME( "Send msg?\n" );
3697 
3698     return DP_OK;
3699 }
3700 
3701 static HRESULT DP_IF_SetPlayerName( IDirectPlayImpl *This, DPID idPlayer, DPNAME *lpPlayerName,
3702         DWORD dwFlags, BOOL bAnsi )
3703 {
3704   lpPlayerList lpPList;
3705 
3706   TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3707          This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3708 
3709   if( This->dp2->connectionInitialized == NO_PROVIDER )
3710   {
3711     return DPERR_UNINITIALIZED;
3712   }
3713 
3714   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3715   {
3716     return DPERR_INVALIDGROUP;
3717   }
3718 
3719   DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3720 
3721   /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3722   FIXME( "Message not sent and dwFlags ignored\n" );
3723 
3724   return DP_OK;
3725 }
3726 
3727 static HRESULT WINAPI IDirectPlay2AImpl_SetPlayerName( IDirectPlay2A *iface, DPID player,
3728         DPNAME *name, DWORD flags )
3729 {
3730     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3731     return IDirectPlayX_SetPlayerName( &This->IDirectPlay4A_iface, player, name, flags );
3732 }
3733 
3734 static HRESULT WINAPI IDirectPlay2Impl_SetPlayerName( IDirectPlay2 *iface, DPID player,
3735         DPNAME *name, DWORD flags )
3736 {
3737     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3738     return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
3739 }
3740 
3741 static HRESULT WINAPI IDirectPlay3AImpl_SetPlayerName( IDirectPlay3A *iface, DPID player,
3742         DPNAME *name, DWORD flags )
3743 {
3744     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3745     return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
3746 }
3747 
3748 static HRESULT WINAPI IDirectPlay3Impl_SetPlayerName( IDirectPlay3 *iface, DPID player,
3749         DPNAME *name, DWORD flags )
3750 {
3751     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3752     return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
3753 }
3754 
3755 static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
3756         DPNAME *lpPlayerName, DWORD dwFlags )
3757 {
3758     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3759     return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3760 }
3761 
3762 static HRESULT WINAPI IDirectPlay4Impl_SetPlayerName( IDirectPlay4 *iface, DPID idPlayer,
3763         DPNAME *lpPlayerName, DWORD dwFlags )
3764 {
3765     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3766     return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3767 }
3768 
3769 static HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
3770         DWORD dwFlags, BOOL bInitial, BOOL bAnsi  )
3771 {
3772   DWORD            dwRequiredSize;
3773   LPDPSESSIONDESC2 lpTempSessDesc;
3774 
3775   TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3776          This, lpSessDesc, dwFlags, bInitial, bAnsi );
3777 
3778   if( This->dp2->connectionInitialized == NO_PROVIDER )
3779   {
3780     return DPERR_UNINITIALIZED;
3781   }
3782 
3783   if( dwFlags )
3784   {
3785     return DPERR_INVALIDPARAMS;
3786   }
3787 
3788   /* Only the host is allowed to update the session desc */
3789   if( !This->dp2->bHostInterface )
3790   {
3791     return DPERR_ACCESSDENIED;
3792   }
3793 
3794   /* FIXME: Copy into This->dp2->lpSessionDesc */
3795   dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3796   lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3797 
3798   if( lpTempSessDesc == NULL )
3799   {
3800     return DPERR_OUTOFMEMORY;
3801   }
3802 
3803   /* Free the old */
3804   HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3805 
3806   This->dp2->lpSessionDesc = lpTempSessDesc;
3807   /* Set the new */
3808   DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3809   if( bInitial )
3810   {
3811     /*Initializing session GUID*/
3812     CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3813   }
3814   /* If this is an external invocation of the interface, we should be
3815    * letting everyone know that things have changed. Otherwise this is
3816    * just an initialization and it doesn't need to be propagated.
3817    */
3818   if( !bInitial )
3819   {
3820     FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3821   }
3822 
3823   return DP_OK;
3824 }
3825 
3826 static HRESULT WINAPI IDirectPlay2AImpl_SetSessionDesc( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
3827         DWORD flags )
3828 {
3829     IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
3830     return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4A_iface, sdesc, flags );
3831 }
3832 
3833 static HRESULT WINAPI IDirectPlay2Impl_SetSessionDesc( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
3834         DWORD flags )
3835 {
3836     IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
3837     return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
3838 }
3839 
3840 static HRESULT WINAPI IDirectPlay3AImpl_SetSessionDesc( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
3841         DWORD flags )
3842 {
3843     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3844     return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
3845 }
3846 
3847 static HRESULT WINAPI IDirectPlay3Impl_SetSessionDesc( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
3848         DWORD flags )
3849 {
3850     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3851     return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
3852 }
3853 
3854 static HRESULT WINAPI IDirectPlay4AImpl_SetSessionDesc( IDirectPlay4A *iface,
3855         DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
3856 {
3857     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3858     return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3859 }
3860 
3861 static HRESULT WINAPI IDirectPlay4Impl_SetSessionDesc( IDirectPlay4 *iface,
3862         DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
3863 {
3864     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3865     return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3866 }
3867 
3868 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3869 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3870 {
3871   DWORD dwSize = 0;
3872 
3873   if( lpSessDesc == NULL )
3874   {
3875     /* Hmmm..don't need any size? */
3876     ERR( "NULL lpSessDesc\n" );
3877     return dwSize;
3878   }
3879 
3880   dwSize += sizeof( *lpSessDesc );
3881 
3882   if( bAnsi )
3883   {
3884     if( lpSessDesc->u1.lpszSessionNameA )
3885     {
3886       dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3887     }
3888 
3889     if( lpSessDesc->u2.lpszPasswordA )
3890     {
3891       dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3892     }
3893   }
3894   else /* UNICODE */
3895   {
3896     if( lpSessDesc->u1.lpszSessionName )
3897     {
3898       dwSize += sizeof( WCHAR ) *
3899         ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3900     }
3901 
3902     if( lpSessDesc->u2.lpszPassword )
3903     {
3904       dwSize += sizeof( WCHAR ) *
3905         ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3906     }
3907   }
3908 
3909   return dwSize;
3910 }
3911 
3912 /* Assumes that contiguous buffers are already allocated. */
3913 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3914                                 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3915 {
3916   BYTE* lpStartOfFreeSpace;
3917 
3918   if( lpSessionDest == NULL )
3919   {
3920     ERR( "NULL lpSessionDest\n" );
3921     return;
3922   }
3923 
3924   CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3925 
3926   lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3927 
3928   if( bAnsi )
3929   {
3930     if( lpSessionSrc->u1.lpszSessionNameA )
3931     {
3932       lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3933                 lpSessionDest->u1.lpszSessionNameA );
3934       lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3935       lpStartOfFreeSpace +=
3936         lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3937     }
3938 
3939     if( lpSessionSrc->u2.lpszPasswordA )
3940     {
3941       lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3942                 lpSessionDest->u2.lpszPasswordA );
3943       lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3944     }
3945   }
3946   else /* UNICODE */
3947   {
3948     if( lpSessionSrc->u1.lpszSessionName )
3949     {
3950       lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3951                 lpSessionDest->u1.lpszSessionName );
3952       lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3953       lpStartOfFreeSpace += sizeof(WCHAR) *
3954         ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3955     }
3956 
3957     if( lpSessionSrc->u2.lpszPassword )
3958     {
3959       lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3960                 lpSessionDest->u2.lpszPassword );
3961       lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3962     }
3963   }
3964 }
3965 
3966 static HRESULT WINAPI IDirectPlay3AImpl_AddGroupToGroup( IDirectPlay3A *iface, DPID parent,
3967         DPID group )
3968 {
3969     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
3970     return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4A_iface, parent, group );
3971 }
3972 
3973 static HRESULT WINAPI IDirectPlay3Impl_AddGroupToGroup( IDirectPlay3 *iface, DPID parent,
3974         DPID group )
3975 {
3976     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
3977     return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
3978 }
3979 
3980 static HRESULT WINAPI IDirectPlay4AImpl_AddGroupToGroup( IDirectPlay4A *iface, DPID parent,
3981         DPID group )
3982 {
3983     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3984     return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
3985 }
3986 
3987 static HRESULT WINAPI IDirectPlay4Impl_AddGroupToGroup( IDirectPlay4 *iface, DPID parent,
3988         DPID group )
3989 {
3990     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
3991     lpGroupData gdata;
3992     lpGroupList glist;
3993 
3994     TRACE( "(%p)->(0x%08x,0x%08x)\n", This, parent, group );
3995 
3996     if ( This->dp2->connectionInitialized == NO_PROVIDER )
3997         return DPERR_UNINITIALIZED;
3998 
3999     if ( !DP_FindAnyGroup(This, parent ) )
4000         return DPERR_INVALIDGROUP;
4001 
4002     if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
4003         return DPERR_INVALIDGROUP;
4004 
4005     /* Create a player list (ie "shortcut" ) */
4006     glist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *glist ) );
4007     if ( !glist )
4008         return DPERR_CANTADDPLAYER;
4009 
4010     /* Add the shortcut */
4011     gdata->uRef++;
4012     glist->lpGData = gdata;
4013 
4014     /* Add the player to the list of players for this group */
4015     DPQ_INSERT( gdata->groups, glist, groups );
4016 
4017     /* Send a ADDGROUPTOGROUP message */
4018     FIXME( "Not sending message\n" );
4019 
4020     return DP_OK;
4021 }
4022 
4023 static HRESULT DP_IF_CreateGroupInGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID idParentGroup,
4024         DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags,
4025         BOOL bAnsi )
4026 {
4027   lpGroupData lpGParentData;
4028   lpGroupList lpGList;
4029   lpGroupData lpGData;
4030 
4031   TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
4032          This, idParentGroup, lpidGroup, lpGroupName, lpData,
4033          dwDataSize, dwFlags, bAnsi );
4034 
4035   if( This->dp2->connectionInitialized == NO_PROVIDER )
4036   {
4037     return DPERR_UNINITIALIZED;
4038   }
4039 
4040   /* Verify that the specified parent is valid */
4041   if( ( lpGParentData = DP_FindAnyGroup(This, idParentGroup ) ) == NULL )
4042     return DPERR_INVALIDGROUP;
4043 
4044   lpGData = DP_CreateGroup(This, lpidGroup, lpGroupName, dwFlags, idParentGroup, bAnsi );
4045 
4046   if( lpGData == NULL )
4047   {
4048     return DPERR_CANTADDPLAYER; /* yes player not group */
4049   }
4050 
4051   /* Something else is referencing this data */
4052   lpGData->uRef++;
4053 
4054   DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
4055 
4056   /* The list has now been inserted into the interface group list. We now
4057      need to put a "shortcut" to this group in the parent group */
4058   lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
4059   if( lpGList == NULL )
4060   {
4061     FIXME( "Memory leak\n" );
4062     return DPERR_CANTADDPLAYER; /* yes player not group */
4063   }
4064 
4065   lpGList->lpGData = lpGData;
4066 
4067   DPQ_INSERT( lpGParentData->groups, lpGList, groups );
4068 
4069   /* Let the SP know that we've created this group */
4070   if( This->dp2->spData.lpCB->CreateGroup )
4071   {
4072     DPSP_CREATEGROUPDATA data;
4073 
4074     TRACE( "Calling SP CreateGroup\n" );
4075 
4076     data.idGroup           = *lpidGroup;
4077     data.dwFlags           = dwFlags;
4078     data.lpSPMessageHeader = lpMsgHdr;
4079     data.lpISP             = This->dp2->spData.lpISP;
4080 
4081     (*This->dp2->spData.lpCB->CreateGroup)( &data );
4082   }
4083 
4084   /* Inform all other peers of the creation of a new group. If there are
4085    * no peers keep this quiet.
4086    */
4087   if( This->dp2->lpSessionDesc &&
4088       ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
4089   {
4090     DPMSG_CREATEPLAYERORGROUP msg;
4091 
4092     msg.dwType = DPSYS_CREATEPLAYERORGROUP;
4093     msg.dwPlayerType = DPPLAYERTYPE_GROUP;
4094     msg.dpId = *lpidGroup;
4095     msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
4096     msg.lpData = lpData;
4097     msg.dwDataSize = dwDataSize;
4098     msg.dpnName = *lpGroupName;
4099 
4100     /* FIXME: Correct to just use send effectively? */
4101     /* FIXME: Should size include data w/ message or just message "header" */
4102     /* FIXME: Check return code */
4103     IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
4104             sizeof( msg ), 0, 0, NULL, NULL );
4105   }
4106 
4107   return DP_OK;
4108 }
4109 
4110 static HRESULT WINAPI IDirectPlay3AImpl_CreateGroupInGroup( IDirectPlay3A *iface, DPID parent,
4111         DPID *group, DPNAME *name, void *data, DWORD size, DWORD flags )
4112 {
4113     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4114     return IDirectPlayX_CreateGroupInGroup( &This->IDirectPlay4A_iface, parent, group, name,
4115             data, size, flags );
4116 }
4117 
4118 static HRESULT WINAPI IDirectPlay3Impl_CreateGroupInGroup( IDirectPlay3 *iface, DPID parent,
4119         DPID *group, DPNAME *name, void *data, DWORD size, DWORD flags )
4120 {
4121     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4122     return IDirectPlayX_CreateGroupInGroup( &This->IDirectPlay4_iface, parent, group, name,
4123             data, size, flags );
4124 }
4125 
4126 static HRESULT WINAPI IDirectPlay4AImpl_CreateGroupInGroup( IDirectPlay4A *iface,
4127         DPID idParentGroup, DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize,
4128         DWORD dwFlags )
4129 {
4130     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4131 
4132     *lpidGroup = DPID_UNKNOWN;
4133 
4134     return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
4135             dwDataSize, dwFlags, TRUE );
4136 }
4137 
4138 static HRESULT WINAPI IDirectPlay4Impl_CreateGroupInGroup( IDirectPlay4 *iface, DPID idParentGroup,
4139         DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
4140 {
4141     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4142 
4143     *lpidGroup = DPID_UNKNOWN;
4144 
4145     return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
4146             dwDataSize, dwFlags, FALSE );
4147 }
4148 
4149 static HRESULT WINAPI IDirectPlay3AImpl_DeleteGroupFromGroup( IDirectPlay3A *iface, DPID parent,
4150         DPID group )
4151 {
4152     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4153     return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4A_iface, parent, group );
4154 }
4155 
4156 static HRESULT WINAPI IDirectPlay3Impl_DeleteGroupFromGroup( IDirectPlay3 *iface, DPID parent,
4157         DPID group )
4158 {
4159     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4160     return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
4161 }
4162 
4163 static HRESULT WINAPI IDirectPlay4AImpl_DeleteGroupFromGroup( IDirectPlay4A *iface, DPID parent,
4164         DPID group )
4165 {
4166     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4167     return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
4168 }
4169 
4170 static HRESULT WINAPI IDirectPlay4Impl_DeleteGroupFromGroup( IDirectPlay4 *iface, DPID parent,
4171         DPID group )
4172 {
4173     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4174     lpGroupList glist;
4175     lpGroupData parentdata;
4176 
4177     TRACE("(%p)->(0x%08x,0x%08x)\n", This, parent, group );
4178 
4179     /* Is the parent group valid? */
4180     if ( ( parentdata = DP_FindAnyGroup(This, parent ) ) == NULL )
4181         return DPERR_INVALIDGROUP;
4182 
4183     /* Remove the group from the parent group queue */
4184     DPQ_REMOVE_ENTRY( parentdata->groups, groups, lpGData->dpid, ==, group, glist );
4185 
4186     if ( glist == NULL )
4187         return DPERR_INVALIDGROUP;
4188 
4189     /* Decrement the ref count */
4190     glist->lpGData->uRef--;
4191 
4192     /* Free up the list item */
4193     HeapFree( GetProcessHeap(), 0, glist );
4194 
4195     /* Should send a DELETEGROUPFROMGROUP message */
4196     FIXME( "message not sent\n" );
4197 
4198     return DP_OK;
4199 }
4200 
4201 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
4202                                     LPDWORD lpdwBufSize )
4203 {
4204   DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
4205   HRESULT                  hr;
4206 
4207   dpCompoundAddress.dwDataSize = sizeof( GUID );
4208   dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
4209   dpCompoundAddress.lpData = lpcSpGuid;
4210 
4211   *lplpAddrBuf = NULL;
4212   *lpdwBufSize = 0;
4213 
4214   hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
4215                                   lpdwBufSize, TRUE );
4216 
4217   if( hr != DPERR_BUFFERTOOSMALL )
4218   {
4219     ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
4220     return FALSE;
4221   }
4222 
4223   /* Now allocate the buffer */
4224   *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4225                             *lpdwBufSize );
4226 
4227   hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
4228                                   lpdwBufSize, TRUE );
4229   if( FAILED(hr) )
4230   {
4231     ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
4232     return FALSE;
4233   }
4234 
4235   return TRUE;
4236 }
4237 
4238 static HRESULT WINAPI IDirectPlay3AImpl_EnumConnections( IDirectPlay3A *iface,
4239         const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
4240 {
4241     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4242     return IDirectPlayX_EnumConnections( &This->IDirectPlay4A_iface, application, enumcb, context,
4243             flags );
4244 }
4245 
4246 static HRESULT WINAPI IDirectPlay3Impl_EnumConnections( IDirectPlay3 *iface,
4247         const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
4248 {
4249     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4250     return IDirectPlayX_EnumConnections( &This->IDirectPlay4_iface, application, enumcb, context,
4251             flags );
4252 }
4253 
4254 static HRESULT WINAPI IDirectPlay4AImpl_EnumConnections( IDirectPlay4A *iface,
4255         const GUID *lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, void *lpContext,
4256         DWORD dwFlags )
4257 {
4258   IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4259   TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
4260 
4261   /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
4262   if( dwFlags == 0 )
4263   {
4264     dwFlags = DPCONNECTION_DIRECTPLAY;
4265   }
4266 
4267   if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
4268           ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
4269     )
4270   {
4271     return DPERR_INVALIDFLAGS;
4272   }
4273 
4274   if( !lpEnumCallback )
4275   {
4276      return DPERR_INVALIDPARAMS;
4277   }
4278 
4279   /* Enumerate DirectPlay service providers */
4280   if( dwFlags & DPCONNECTION_DIRECTPLAY )
4281   {
4282     HKEY hkResult;
4283     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4284     LPCSTR guidDataSubKey  = "Guid";
4285     char subKeyName[51];
4286     DWORD dwIndex, sizeOfSubKeyName=50;
4287     FILETIME filetime;
4288 
4289     /* Need to loop over the service providers in the registry */
4290     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4291                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4292     {
4293       /* Hmmm. Does this mean that there are no service providers? */
4294       ERR(": no service providers?\n");
4295       return DP_OK;
4296     }
4297 
4298 
4299     /* Traverse all the service providers we have available */
4300     for( dwIndex=0;
4301          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4302                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4303          ++dwIndex, sizeOfSubKeyName=51 )
4304     {
4305 
4306       HKEY     hkServiceProvider;
4307       GUID     serviceProviderGUID;
4308       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
4309       char     returnBuffer[51];
4310       WCHAR    buff[51];
4311       DPNAME   dpName;
4312       BOOL     bBuildPass;
4313 
4314       LPVOID                   lpAddressBuffer = NULL;
4315       DWORD                    dwAddressBufferSize = 0;
4316 
4317       TRACE(" this time through: %s\n", subKeyName );
4318 
4319       /* Get a handle for this particular service provider */
4320       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4321                          &hkServiceProvider ) != ERROR_SUCCESS )
4322       {
4323          ERR(": what the heck is going on?\n" );
4324          continue;
4325       }
4326 
4327       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4328                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
4329                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4330       {
4331         ERR(": missing GUID registry data members\n" );
4332         RegCloseKey(hkServiceProvider);
4333         continue;
4334       }
4335       RegCloseKey(hkServiceProvider);
4336 
4337       /* FIXME: Check return types to ensure we're interpreting data right */
4338       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, ARRAY_SIZE( buff ));
4339       CLSIDFromString( buff, &serviceProviderGUID );
4340       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4341 
4342       /* Fill in the DPNAME struct for the service provider */
4343       dpName.dwSize             = sizeof( dpName );
4344       dpName.dwFlags            = 0;
4345       dpName.u1.lpszShortNameA = subKeyName;
4346       dpName.u2.lpszLongNameA  = NULL;
4347 
4348       /* Create the compound address for the service provider.
4349        * NOTE: This is a gruesome architectural scar right now.  DP
4350        * uses DPL and DPL uses DP.  Nasty stuff. This may be why the
4351        * native dll just gets around this little bit by allocating an
4352        * 80 byte buffer which isn't even filled with a valid compound
4353        * address. Oh well. Creating a proper compound address is the
4354        * way to go anyways despite this method taking slightly more
4355        * heap space and realtime :) */
4356 
4357       bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
4358                                            &lpAddressBuffer,
4359                                            &dwAddressBufferSize );
4360       if( !bBuildPass )
4361       {
4362         ERR( "Can't build compound addr\n" );
4363         return DPERR_GENERIC;
4364       }
4365 
4366       /* The enumeration will return FALSE if we are not to continue */
4367       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
4368                            &dpName, dwFlags, lpContext ) )
4369       {
4370          HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4371          return DP_OK;
4372       }
4373       HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4374     }
4375   }
4376 
4377   /* Enumerate DirectPlayLobby service providers */
4378   if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
4379   {
4380     HKEY hkResult;
4381     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4382     LPCSTR guidDataSubKey  = "Guid";
4383     char subKeyName[51];
4384     DWORD dwIndex, sizeOfSubKeyName=50;
4385     FILETIME filetime;
4386 
4387     /* Need to loop over the service providers in the registry */
4388     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4389                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4390     {
4391       TRACE("No Lobby Providers have been registered.\n");
4392       return DP_OK;
4393     }
4394 
4395 
4396     /* Traverse all the lobby providers we have available */
4397     for( dwIndex=0;
4398          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4399                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4400          ++dwIndex, sizeOfSubKeyName=51 )
4401     {
4402 
4403       HKEY     hkServiceProvider;
4404       GUID     serviceProviderGUID;
4405       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
4406       char     returnBuffer[51];
4407       WCHAR    buff[51];
4408       DPNAME   dpName;
4409       HRESULT  hr;
4410 
4411       DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
4412       LPVOID                   lpAddressBuffer = NULL;
4413       DWORD                    dwAddressBufferSize = 0;
4414 
4415       TRACE(" this time through: %s\n", subKeyName );
4416 
4417       /* Get a handle for this particular service provider */
4418       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4419                          &hkServiceProvider ) != ERROR_SUCCESS )
4420       {
4421          ERR(": what the heck is going on?\n" );
4422          continue;
4423       }
4424 
4425       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4426                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
4427                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4428       {
4429         ERR(": missing GUID registry data members\n" );
4430         RegCloseKey(hkServiceProvider);
4431         continue;
4432       }
4433       RegCloseKey(hkServiceProvider);
4434 
4435       /* FIXME: Check return types to ensure we're interpreting data right */
4436       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, ARRAY_SIZE( buff ));
4437       CLSIDFromString( buff, &serviceProviderGUID );
4438       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4439 
4440       /* Fill in the DPNAME struct for the service provider */
4441       dpName.dwSize             = sizeof( dpName );
4442       dpName.dwFlags            = 0;
4443       dpName.u1.lpszShortNameA = subKeyName;
4444       dpName.u2.lpszLongNameA  = NULL;
4445 
4446       /* Create the compound address for the service provider.
4447          NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
4448                nast stuff. This may be why the native dll just gets around this little bit by
4449                allocating an 80 byte buffer which isn't even a filled with a valid compound
4450                address. Oh well. Creating a proper compound address is the way to go anyways
4451                despite this method taking slightly more heap space and realtime :) */
4452 
4453       dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
4454       dpCompoundAddress.dwDataSize   = sizeof( GUID );
4455       dpCompoundAddress.lpData       = &serviceProviderGUID;
4456 
4457       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
4458                                      &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
4459       {
4460         ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
4461         return hr;
4462       }
4463 
4464       /* Now allocate the buffer */
4465       lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
4466 
4467       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
4468                                      &dwAddressBufferSize, TRUE ) ) != DP_OK )
4469       {
4470         ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
4471         HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4472         return hr;
4473       }
4474 
4475       /* The enumeration will return FALSE if we are not to continue */
4476       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
4477                            &dpName, dwFlags, lpContext ) )
4478       {
4479          HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4480          return DP_OK;
4481       }
4482       HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4483     }
4484   }
4485 
4486   return DP_OK;
4487 }
4488 
4489 static HRESULT WINAPI IDirectPlay4Impl_EnumConnections( IDirectPlay4 *iface,
4490         const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
4491 {
4492     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4493     return IDirectPlayX_EnumConnections( &This->IDirectPlay4A_iface, application, enumcb, context,
4494             flags );
4495 }
4496 
4497 static HRESULT WINAPI IDirectPlay3AImpl_EnumGroupsInGroup( IDirectPlay3A *iface, DPID group,
4498         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
4499 {
4500     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4501     return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4A_iface, group, instance,
4502             enumplayercb, context, flags );
4503 }
4504 
4505 static HRESULT WINAPI IDirectPlay3Impl_EnumGroupsInGroup( IDirectPlay3 *iface, DPID group,
4506         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
4507 {
4508     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4509     return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, group, instance,
4510             enumplayercb, context, flags );
4511 }
4512 
4513 static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupsInGroup( IDirectPlay4A *iface, DPID group,
4514         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
4515 {
4516     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4517     return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, group, instance,
4518             enumplayercb, context, flags );
4519 }
4520 
4521 static HRESULT WINAPI IDirectPlay4Impl_EnumGroupsInGroup( IDirectPlay4 *iface, DPID group,
4522         GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
4523 {
4524     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4525     lpGroupList glist;
4526     lpGroupData gdata;
4527 
4528     FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
4529             context, flags );
4530 
4531     if ( This->dp2->connectionInitialized == NO_PROVIDER )
4532         return DPERR_UNINITIALIZED;
4533 
4534     if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
4535         return DPERR_INVALIDGROUP;
4536 
4537     if ( DPQ_IS_EMPTY( gdata->groups ) )
4538         return DP_OK;
4539 
4540 
4541     for( glist = DPQ_FIRST( gdata->groups ); ; glist = DPQ_NEXT( glist->groups ) )
4542     {
4543         /* FIXME: Should check flags for match here */
4544         if ( !(*enumplayercb)( glist->lpGData->dpid, DPPLAYERTYPE_GROUP, &glist->lpGData->name,
4545                     flags, context ) )
4546             return DP_OK; /* User requested break */
4547 
4548         if ( DPQ_IS_ENDOFLIST( glist->groups ) )
4549             break;
4550     }
4551 
4552     return DP_OK;
4553 }
4554 
4555 static HRESULT WINAPI IDirectPlay3AImpl_GetGroupConnectionSettings( IDirectPlay3A *iface,
4556         DWORD flags, DPID group, void *data, DWORD *size )
4557 {
4558     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4559     return IDirectPlayX_GetGroupConnectionSettings( &This->IDirectPlay4A_iface, flags, group,
4560             data, size );
4561 }
4562 
4563 static HRESULT WINAPI IDirectPlay3Impl_GetGroupConnectionSettings( IDirectPlay3 *iface,
4564         DWORD flags, DPID group, void *data, DWORD *size )
4565 {
4566     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4567     return IDirectPlayX_GetGroupConnectionSettings( &This->IDirectPlay4_iface, flags, group,
4568             data, size );
4569 }
4570 
4571 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupConnectionSettings( IDirectPlay4A *iface,
4572         DWORD flags, DPID group, void *data, DWORD *size )
4573 {
4574     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4575     FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
4576     return DP_OK;
4577 }
4578 
4579 static HRESULT WINAPI IDirectPlay4Impl_GetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
4580         DPID group, void *data, DWORD *size )
4581 {
4582     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4583     FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
4584     return DP_OK;
4585 }
4586 
4587 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4588     REFGUID         guidDataType,
4589     DWORD           dwDataSize,
4590     LPCVOID         lpData,
4591     LPVOID          lpContext )
4592 {
4593   /* Looking for the GUID of the provider to load */
4594   if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
4595       ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4596     )
4597   {
4598     TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4599            debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4600 
4601     if( dwDataSize != sizeof( GUID ) )
4602     {
4603       ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4604     }
4605 
4606     memcpy( lpContext, lpData, dwDataSize );
4607 
4608     /* There shouldn't be more than 1 GUID/compound address */
4609     return FALSE;
4610   }
4611 
4612   /* Still waiting for what we want */
4613   return TRUE;
4614 }
4615 
4616 
4617 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4618 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4619 {
4620   UINT i;
4621   LPCSTR spSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4622   LPCSTR lpSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4623   LPCSTR guidDataSubKey   = "Guid";
4624   LPCSTR majVerDataSubKey = "dwReserved1";
4625   LPCSTR minVerDataSubKey = "dwReserved2";
4626   LPCSTR pathSubKey       = "Path";
4627 
4628   TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4629 
4630   /* FIXME: Cloned code with a quick hack. */
4631   for( i=0; i<2; i++ )
4632   {
4633     HKEY hkResult;
4634     LPCSTR searchSubKey;
4635     char subKeyName[51];
4636     DWORD dwIndex, sizeOfSubKeyName=50;
4637     FILETIME filetime;
4638 
4639     (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4640     *lpbIsDpSp = (i == 0);
4641 
4642 
4643     /* Need to loop over the service providers in the registry */
4644     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4645                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4646     {
4647       /* Hmmm. Does this mean that there are no service providers? */
4648       ERR(": no service providers?\n");
4649       return 0;
4650     }
4651 
4652     /* Traverse all the service providers we have available */
4653     for( dwIndex=0;
4654          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4655                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4656          ++dwIndex, sizeOfSubKeyName=51 )
4657     {
4658 
4659       HKEY     hkServiceProvider;
4660       GUID     serviceProviderGUID;
4661       DWORD    returnType, sizeOfReturnBuffer = 255;
4662       char     returnBuffer[256];
4663       WCHAR    buff[51];
4664       DWORD    dwTemp, len;
4665 
4666       TRACE(" this time through: %s\n", subKeyName );
4667 
4668       /* Get a handle for this particular service provider */
4669       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4670                          &hkServiceProvider ) != ERROR_SUCCESS )
4671       {
4672          ERR(": what the heck is going on?\n" );
4673          continue;
4674       }
4675 
4676       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4677                             NULL, &returnType, (LPBYTE)returnBuffer,
4678                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4679       {
4680         ERR(": missing GUID registry data members\n" );
4681         continue;
4682       }
4683 
4684       /* FIXME: Check return types to ensure we're interpreting data right */
4685       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, ARRAY_SIZE( buff ));
4686       CLSIDFromString( buff, &serviceProviderGUID );
4687       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4688 
4689       /* Determine if this is the Service Provider that the user asked for */
4690       if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4691       {
4692         continue;
4693       }
4694 
4695       if( i == 0 ) /* DP SP */
4696       {
4697         len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4698         lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4699         MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4700       }
4701 
4702       sizeOfReturnBuffer = 255;
4703 
4704       /* Get dwReserved1 */
4705       if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4706                             NULL, &returnType, (LPBYTE)returnBuffer,
4707                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4708       {
4709          ERR(": missing dwReserved1 registry data members\n") ;
4710          continue;
4711       }
4712 
4713       if( i == 0 )
4714           memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4715 
4716       sizeOfReturnBuffer = 255;
4717 
4718       /* Get dwReserved2 */
4719       if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4720                             NULL, &returnType, (LPBYTE)returnBuffer,
4721                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4722       {
4723          ERR(": missing dwReserved1 registry data members\n") ;
4724          continue;
4725       }
4726 
4727       if( i == 0 )
4728           memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4729 
4730       sizeOfReturnBuffer = 255;
4731 
4732       /* Get the path for this service provider */
4733       if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4734                             NULL, NULL, (LPBYTE)returnBuffer,
4735                             &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4736       {
4737         ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4738         continue;
4739       }
4740 
4741       TRACE( "Loading %s\n", returnBuffer );
4742       return LoadLibraryA( returnBuffer );
4743     }
4744   }
4745 
4746   return 0;
4747 }
4748 
4749 static HRESULT DP_InitializeDPSP( IDirectPlayImpl *This, HMODULE hServiceProvider )
4750 {
4751   HRESULT hr;
4752   LPDPSP_SPINIT SPInit;
4753 
4754   /* Initialize the service provider by calling SPInit */
4755   SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4756 
4757   if( SPInit == NULL )
4758   {
4759     ERR( "Service provider doesn't provide SPInit interface?\n" );
4760     FreeLibrary( hServiceProvider );
4761     return DPERR_UNAVAILABLE;
4762   }
4763 
4764   TRACE( "Calling SPInit (DP SP entry point)\n" );
4765 
4766   hr = (*SPInit)( &This->dp2->spData );
4767 
4768   if( FAILED(hr) )
4769   {
4770     ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4771     FreeLibrary( hServiceProvider );
4772     return hr;
4773   }
4774 
4775   /* FIXME: Need to verify the sanity of the returned callback table
4776    *        using IsBadCodePtr */
4777   This->dp2->bSPInitialized = TRUE;
4778 
4779   /* This interface is now initialized as a DP object */
4780   This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4781 
4782   /* Store the handle of the module so that we can unload it later */
4783   This->dp2->hServiceProvider = hServiceProvider;
4784 
4785   return hr;
4786 }
4787 
4788 static HRESULT DP_InitializeDPLSP( IDirectPlayImpl *This, HMODULE hLobbyProvider )
4789 {
4790   HRESULT hr;
4791   LPSP_INIT DPLSPInit;
4792 
4793   /* Initialize the service provider by calling SPInit */
4794   DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4795 
4796   if( DPLSPInit == NULL )
4797   {
4798     ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4799     FreeLibrary( hLobbyProvider );
4800     return DPERR_UNAVAILABLE;
4801   }
4802 
4803   TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4804 
4805   hr = (*DPLSPInit)( &This->dp2->dplspData );
4806 
4807   if( FAILED(hr) )
4808   {
4809     ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4810     FreeLibrary( hLobbyProvider );
4811     return hr;
4812   }
4813 
4814   /* FIXME: Need to verify the sanity of the returned callback table
4815    *        using IsBadCodePtr */
4816 
4817   This->dp2->bDPLSPInitialized = TRUE;
4818 
4819   /* This interface is now initialized as a lobby object */
4820   This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4821 
4822   /* Store the handle of the module so that we can unload it later */
4823   This->dp2->hDPLobbyProvider = hLobbyProvider;
4824 
4825   return hr;
4826 }
4827 
4828 static HRESULT WINAPI IDirectPlay3AImpl_InitializeConnection( IDirectPlay3A *iface,
4829         void *connection, DWORD flags )
4830 {
4831     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4832     return IDirectPlayX_InitializeConnection( &This->IDirectPlay4A_iface, connection, flags );
4833 }
4834 
4835 static HRESULT WINAPI IDirectPlay3Impl_InitializeConnection( IDirectPlay3 *iface,
4836         void *connection, DWORD flags )
4837 {
4838     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4839     return IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, flags );
4840 }
4841 
4842 static HRESULT WINAPI IDirectPlay4AImpl_InitializeConnection( IDirectPlay4A *iface,
4843         void *connection, DWORD flags )
4844 {
4845     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4846     return IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, flags );
4847 }
4848 
4849 static HRESULT WINAPI IDirectPlay4Impl_InitializeConnection( IDirectPlay4 *iface,
4850         void *connection, DWORD flags )
4851 {
4852     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4853     HMODULE servprov;
4854     GUID sp;
4855     const DWORD size = 80; /* FIXME: Need to calculate it correctly */
4856     BOOL is_dp_sp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4857     HRESULT hr;
4858 
4859     TRACE( "(%p)->(%p,0x%08x)\n", This, connection, flags );
4860 
4861     if ( !connection )
4862         return DPERR_INVALIDPARAMS;
4863 
4864     if ( flags )
4865         return DPERR_INVALIDFLAGS;
4866 
4867     if ( This->dp2->connectionInitialized != NO_PROVIDER )
4868         return DPERR_ALREADYINITIALIZED;
4869 
4870     /* Find out what the requested SP is and how large this buffer is */
4871     hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, connection, size, &sp );
4872 
4873     if ( FAILED(hr) )
4874     {
4875         ERR( "Invalid compound address?\n" );
4876         return DPERR_UNAVAILABLE;
4877     }
4878 
4879     /* Load the service provider */
4880     servprov = DP_LoadSP( &sp, &This->dp2->spData, &is_dp_sp );
4881 
4882     if ( !servprov )
4883     {
4884         ERR( "Unable to load service provider %s\n", debugstr_guid(&sp) );
4885         return DPERR_UNAVAILABLE;
4886     }
4887 
4888     if ( is_dp_sp )
4889     {
4890          /* Fill in what we can of the Service Provider required information.
4891           * The rest was be done in DP_LoadSP
4892           */
4893          This->dp2->spData.lpAddress = connection;
4894          This->dp2->spData.dwAddressSize = size;
4895          This->dp2->spData.lpGuid = &sp;
4896          hr = DP_InitializeDPSP( This, servprov );
4897     }
4898     else
4899     {
4900          This->dp2->dplspData.lpAddress = connection;
4901          hr = DP_InitializeDPLSP( This, servprov );
4902     }
4903 
4904     if ( FAILED(hr) )
4905         return hr;
4906 
4907     return DP_OK;
4908 }
4909 
4910 static HRESULT WINAPI IDirectPlay3AImpl_SecureOpen( IDirectPlay3A *iface,
4911         const DPSESSIONDESC2 *sdesc, DWORD flags, const DPSECURITYDESC *security,
4912         const DPCREDENTIALS *credentials )
4913 {
4914     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4915     return IDirectPlayX_SecureOpen( &This->IDirectPlay4A_iface, sdesc, flags, security,
4916             credentials );
4917 }
4918 
4919 static HRESULT WINAPI IDirectPlay3Impl_SecureOpen( IDirectPlay3 *iface,
4920         const DPSESSIONDESC2 *sdesc, DWORD flags, const DPSECURITYDESC *security,
4921         const DPCREDENTIALS *credentials )
4922 {
4923     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4924     return IDirectPlayX_SecureOpen( &This->IDirectPlay4_iface, sdesc, flags, security,
4925             credentials );
4926 }
4927 
4928 static HRESULT WINAPI IDirectPlay4AImpl_SecureOpen( IDirectPlay4A *iface,
4929         const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
4930         const DPCREDENTIALS *lpCredentials )
4931 {
4932     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4933     return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4934 }
4935 
4936 static HRESULT WINAPI IDirectPlay4Impl_SecureOpen( IDirectPlay4 *iface,
4937         const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
4938         const DPCREDENTIALS *lpCredentials )
4939 {
4940     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4941     return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4942 }
4943 
4944 static HRESULT WINAPI IDirectPlay3AImpl_SendChatMessage( IDirectPlay3A *iface, DPID from, DPID to,
4945         DWORD flags, DPCHAT *chatmsg )
4946 {
4947     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4948     return IDirectPlayX_SendChatMessage( &This->IDirectPlay4A_iface, from, to, flags, chatmsg );
4949 }
4950 
4951 static HRESULT WINAPI IDirectPlay3Impl_SendChatMessage( IDirectPlay3 *iface, DPID from, DPID to,
4952         DWORD flags, DPCHAT *chatmsg )
4953 {
4954     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4955     return IDirectPlayX_SendChatMessage( &This->IDirectPlay4_iface, from, to, flags, chatmsg );
4956 }
4957 
4958 static HRESULT WINAPI IDirectPlay4AImpl_SendChatMessage( IDirectPlay4A *iface, DPID from,
4959         DPID to, DWORD flags, DPCHAT *chatmsg )
4960 {
4961     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4962     FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
4963     return DP_OK;
4964 }
4965 
4966 static HRESULT WINAPI IDirectPlay4Impl_SendChatMessage( IDirectPlay4 *iface, DPID from, DPID to,
4967         DWORD flags, DPCHAT *chatmsg )
4968 {
4969     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4970     FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
4971     return DP_OK;
4972 }
4973 
4974 static HRESULT WINAPI IDirectPlay3AImpl_SetGroupConnectionSettings( IDirectPlay3A *iface,
4975         DWORD flags, DPID group, DPLCONNECTION *connection )
4976 {
4977     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
4978     return IDirectPlayX_SetGroupConnectionSettings( &This->IDirectPlay4A_iface, flags, group,
4979             connection );
4980 }
4981 
4982 static HRESULT WINAPI IDirectPlay3Impl_SetGroupConnectionSettings( IDirectPlay3 *iface,
4983         DWORD flags, DPID group, DPLCONNECTION *connection )
4984 {
4985     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
4986     return IDirectPlayX_SetGroupConnectionSettings( &This->IDirectPlay4_iface, flags, group,
4987             connection );
4988 }
4989 
4990 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupConnectionSettings( IDirectPlay4A *iface,
4991         DWORD flags, DPID group, DPLCONNECTION *connection )
4992 {
4993     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4994     FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
4995     return DP_OK;
4996 }
4997 
4998 static HRESULT WINAPI IDirectPlay4Impl_SetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
4999         DPID group, DPLCONNECTION *connection )
5000 {
5001     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5002     FIXME( "(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
5003     return DP_OK;
5004 }
5005 
5006 static HRESULT WINAPI IDirectPlay3AImpl_StartSession( IDirectPlay3A *iface, DWORD flags,
5007         DPID group )
5008 {
5009     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
5010     return IDirectPlayX_StartSession( &This->IDirectPlay4A_iface, flags, group );
5011 }
5012 
5013 static HRESULT WINAPI IDirectPlay3Impl_StartSession( IDirectPlay3 *iface, DWORD flags,
5014         DPID group )
5015 {
5016     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
5017     return IDirectPlayX_StartSession( &This->IDirectPlay4_iface, flags, group );
5018 }
5019 
5020 static HRESULT WINAPI IDirectPlay4AImpl_StartSession( IDirectPlay4A *iface, DWORD flags,
5021         DPID group )
5022 {
5023     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5024     return IDirectPlayX_StartSession( &This->IDirectPlay4_iface, flags, group );
5025 }
5026 
5027 static HRESULT WINAPI IDirectPlay4Impl_StartSession( IDirectPlay4 *iface, DWORD flags, DPID group )
5028 {
5029     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5030     FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, flags, group );
5031     return DP_OK;
5032 }
5033 
5034 static HRESULT WINAPI IDirectPlay3AImpl_GetGroupFlags( IDirectPlay3A *iface, DPID group,
5035         DWORD *flags )
5036 {
5037     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
5038     return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4A_iface, group, flags );
5039 }
5040 
5041 static HRESULT WINAPI IDirectPlay3Impl_GetGroupFlags( IDirectPlay3 *iface, DPID group,
5042         DWORD *flags )
5043 {
5044     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
5045     return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4_iface, group, flags );
5046 }
5047 
5048 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupFlags( IDirectPlay4A *iface, DPID group,
5049         DWORD *flags )
5050 {
5051     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5052     return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4_iface, group, flags );
5053 }
5054 
5055 static HRESULT WINAPI IDirectPlay4Impl_GetGroupFlags( IDirectPlay4 *iface, DPID group,
5056         DWORD *flags )
5057 {
5058     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5059     FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, flags );
5060     return DP_OK;
5061 }
5062 
5063 static HRESULT WINAPI IDirectPlay3AImpl_GetGroupParent( IDirectPlay3A *iface, DPID group,
5064         DPID *parent )
5065 {
5066     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
5067     return IDirectPlayX_GetGroupParent( &This->IDirectPlay4A_iface, group, parent );
5068 }
5069 
5070 static HRESULT WINAPI IDirectPlay3Impl_GetGroupParent( IDirectPlay3 *iface, DPID group,
5071         DPID *parent )
5072 {
5073     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
5074     return IDirectPlayX_GetGroupParent( &This->IDirectPlay4_iface, group, parent );
5075 }
5076 
5077 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupParent( IDirectPlay4A *iface, DPID group,
5078         DPID *parent )
5079 {
5080     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5081     return IDirectPlayX_GetGroupParent( &This->IDirectPlay4_iface, group, parent );
5082 }
5083 
5084 static HRESULT WINAPI IDirectPlay4Impl_GetGroupParent( IDirectPlay4 *iface, DPID group,
5085         DPID *parent )
5086 {
5087     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5088     lpGroupData gdata;
5089 
5090     TRACE( "(%p)->(0x%08x,%p)\n", This, group, parent );
5091 
5092     if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
5093         return DPERR_INVALIDGROUP;
5094 
5095     *parent = gdata->dpid;
5096 
5097     return DP_OK;
5098 }
5099 
5100 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerAccount( IDirectPlay3A *iface, DPID player,
5101         DWORD flags, void *data, DWORD *size )
5102 {
5103     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
5104     return IDirectPlayX_GetPlayerAccount( &This->IDirectPlay4A_iface, player, flags, data, size );
5105 }
5106 
5107 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerAccount( IDirectPlay3 *iface, DPID player,
5108         DWORD flags, void *data, DWORD *size )
5109 {
5110     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
5111     return IDirectPlayX_GetPlayerAccount( &This->IDirectPlay4_iface, player, flags, data, size );
5112 }
5113 
5114 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAccount( IDirectPlay4A *iface, DPID player,
5115         DWORD flags, void *data, DWORD *size )
5116 {
5117     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5118     FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
5119     return DP_OK;
5120 }
5121 
5122 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAccount( IDirectPlay4 *iface, DPID player,
5123         DWORD flags, void *data, DWORD *size )
5124 {
5125     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5126     FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
5127     return DP_OK;
5128 }
5129 
5130 static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerFlags( IDirectPlay3A *iface, DPID player,
5131         DWORD *flags )
5132 {
5133     IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
5134     return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4A_iface, player, flags );
5135 }
5136 
5137 static HRESULT WINAPI IDirectPlay3Impl_GetPlayerFlags( IDirectPlay3 *iface, DPID player,
5138         DWORD *flags )
5139 {
5140     IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
5141     return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4_iface, player, flags );
5142 }
5143 
5144 static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerFlags( IDirectPlay4A *iface, DPID player,
5145         DWORD *flags )
5146 {
5147     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5148     return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4_iface, player, flags );
5149 }
5150 
5151 static HRESULT WINAPI IDirectPlay4Impl_GetPlayerFlags( IDirectPlay4 *iface, DPID player,
5152         DWORD *flags )
5153 {
5154     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5155     FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, flags );
5156     return DP_OK;
5157 }
5158 
5159 static HRESULT WINAPI IDirectPlay4AImpl_GetGroupOwner( IDirectPlay4A *iface, DPID group,
5160         DPID *owner )
5161 {
5162     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5163     return IDirectPlayX_GetGroupOwner( &This->IDirectPlay4_iface, group, owner );
5164 }
5165 
5166 static HRESULT WINAPI IDirectPlay4Impl_GetGroupOwner( IDirectPlay4 *iface, DPID group,
5167         DPID *owner )
5168 {
5169     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5170     FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, owner );
5171     return DP_OK;
5172 }
5173 
5174 static HRESULT WINAPI IDirectPlay4AImpl_SetGroupOwner( IDirectPlay4A *iface, DPID group,
5175         DPID owner )
5176 {
5177     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5178     return IDirectPlayX_SetGroupOwner( &This->IDirectPlay4_iface, group, owner );
5179 }
5180 
5181 static HRESULT WINAPI IDirectPlay4Impl_SetGroupOwner( IDirectPlay4 *iface, DPID group ,
5182         DPID owner )
5183 {
5184     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5185     FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, owner );
5186     return DP_OK;
5187 }
5188 
5189 static HRESULT WINAPI IDirectPlay4AImpl_SendEx( IDirectPlay4A *iface, DPID from, DPID to,
5190         DWORD flags, void *data, DWORD size, DWORD priority, DWORD timeout, void *context,
5191         DWORD *msgid )
5192 {
5193     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5194     return IDirectPlayX_SendEx( &This->IDirectPlay4_iface, from, to, flags, data, size, priority,
5195             timeout, context, msgid );
5196 }
5197 
5198 static HRESULT WINAPI IDirectPlay4Impl_SendEx( IDirectPlay4 *iface, DPID from, DPID to,
5199         DWORD flags, void *data, DWORD size, DWORD priority, DWORD timeout, void *context,
5200         DWORD *msgid )
5201 {
5202     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5203 
5204     FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p): semi-stub\n",
5205             This, from, to, flags, data, size, priority, timeout, context, msgid );
5206 
5207     if ( This->dp2->connectionInitialized == NO_PROVIDER )
5208         return DPERR_UNINITIALIZED;
5209 
5210     /* FIXME: Add parameter checking */
5211     /* FIXME: First call to this needs to acquire a message id which will be
5212      *        used for multiple sends
5213      */
5214 
5215     /* NOTE: Can't send messages to yourself - this will be trapped in receive */
5216 
5217     /* Verify that the message is being sent from a valid local player. The
5218      * from player may be anonymous DPID_UNKNOWN
5219      */
5220     if ( from != DPID_UNKNOWN && !DP_FindPlayer( This, from ) )
5221     {
5222         WARN( "INFO: Invalid from player 0x%08x\n", from );
5223         return DPERR_INVALIDPLAYER;
5224     }
5225 
5226     /* Verify that the message is being sent to a valid player, group or to
5227      * everyone. If it's valid, send it to those players.
5228      */
5229     if ( to == DPID_ALLPLAYERS )
5230     {
5231         /* See if SP has the ability to multicast. If so, use it */
5232         if ( This->dp2->spData.lpCB->SendToGroupEx )
5233             FIXME( "Use group sendex to group 0\n" );
5234         else if ( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
5235             FIXME( "Use obsolete group send to group 0\n" );
5236         else /* No multicast, multiplicate */
5237             FIXME( "Send to all players using EnumPlayersInGroup\n" );
5238     }
5239     else if ( DP_FindPlayer( This, to ) )
5240     {
5241         /* Have the service provider send this message */
5242         /* FIXME: Could optimize for local interface sends */
5243         return DP_SP_SendEx( This, flags, data, size, priority, timeout, context, msgid );
5244     }
5245     else if ( DP_FindAnyGroup( This, to ) )
5246     {
5247         /* See if SP has the ability to multicast. If so, use it */
5248         if ( This->dp2->spData.lpCB->SendToGroupEx )
5249             FIXME( "Use group sendex\n" );
5250         else if ( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
5251             FIXME( "Use obsolete group send to group\n" );
5252         else /* No multicast, multiplicate */
5253             FIXME( "Send to all players using EnumPlayersInGroup\n" );
5254 
5255     }
5256     else
5257         return DPERR_INVALIDPLAYER;
5258 
5259     /* FIXME: Should return what the send returned */
5260     return DP_OK;
5261 }
5262 
5263 static HRESULT DP_SP_SendEx( IDirectPlayImpl *This, DWORD dwFlags, void *lpData, DWORD dwDataSize,
5264         DWORD dwPriority, DWORD dwTimeout, void *lpContext, DWORD *lpdwMsgID )
5265 {
5266   LPDPMSG lpMElem;
5267 
5268   FIXME( ": stub\n" );
5269 
5270   /* FIXME: This queuing should only be for async messages */
5271 
5272   lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
5273   lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
5274 
5275   CopyMemory( lpMElem->msg, lpData, dwDataSize );
5276 
5277   /* FIXME: Need to queue based on priority */
5278   DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
5279 
5280   return DP_OK;
5281 }
5282 
5283 static HRESULT WINAPI IDirectPlay4AImpl_GetMessageQueue( IDirectPlay4A *iface, DPID from, DPID to,
5284         DWORD flags, DWORD *msgs, DWORD *bytes )
5285 {
5286     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5287     return IDirectPlayX_GetMessageQueue( &This->IDirectPlay4_iface, from, to, flags, msgs, bytes );
5288 }
5289 
5290 static HRESULT WINAPI IDirectPlay4Impl_GetMessageQueue( IDirectPlay4 *iface, DPID from, DPID to,
5291         DWORD flags, DWORD *msgs, DWORD *bytes )
5292 {
5293     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5294     HRESULT hr = DP_OK;
5295 
5296     FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p): semi-stub\n", This, from, to, flags, msgs, bytes );
5297 
5298     /* FIXME: Do we need to do from and to sanity checking here? */
5299     /* FIXME: What about sends which are not immediate? */
5300 
5301     if ( This->dp2->spData.lpCB->GetMessageQueue )
5302     {
5303         DPSP_GETMESSAGEQUEUEDATA data;
5304 
5305         FIXME( "Calling SP GetMessageQueue - is it right?\n" );
5306 
5307         /* FIXME: None of this is documented :( */
5308         data.lpISP        = This->dp2->spData.lpISP;
5309         data.dwFlags      = flags;
5310         data.idFrom       = from;
5311         data.idTo         = to;
5312         data.lpdwNumMsgs  = msgs;
5313         data.lpdwNumBytes = bytes;
5314 
5315         hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
5316     }
5317     else
5318         FIXME( "No SP for GetMessageQueue - fake some data\n" );
5319 
5320     return hr;
5321 }
5322 
5323 static HRESULT dplay_cancelmsg ( IDirectPlayImpl* This, DWORD msgid, DWORD flags, DWORD minprio,
5324         DWORD maxprio )
5325 {
5326     HRESULT hr = DP_OK;
5327 
5328     FIXME( "(%p)->(0x%08x,0x%08x): semi stub\n", This, msgid, flags );
5329 
5330     if ( This->dp2->spData.lpCB->Cancel )
5331     {
5332         DPSP_CANCELDATA data;
5333 
5334         TRACE( "Calling SP Cancel\n" );
5335 
5336         /* FIXME: Undocumented callback */
5337 
5338         data.lpISP          = This->dp2->spData.lpISP;
5339         data.dwFlags        = flags;
5340         data.lprglpvSPMsgID = NULL;
5341         data.cSPMsgID       = msgid;
5342         data.dwMinPriority  = minprio;
5343         data.dwMaxPriority  = maxprio;
5344 
5345         hr = (*This->dp2->spData.lpCB->Cancel)( &data );
5346     }
5347     else
5348         FIXME( "SP doesn't implement Cancel\n" );
5349 
5350     return hr;
5351 }
5352 
5353 static HRESULT WINAPI IDirectPlay4AImpl_CancelMessage( IDirectPlay4A *iface, DWORD msgid,
5354         DWORD flags )
5355 {
5356     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5357     return IDirectPlayX_CancelMessage( &This->IDirectPlay4_iface, msgid, flags );
5358 }
5359 
5360 static HRESULT WINAPI IDirectPlay4Impl_CancelMessage( IDirectPlay4 *iface, DWORD msgid,
5361         DWORD flags )
5362 {
5363     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5364 
5365     if ( flags != 0 )
5366       return DPERR_INVALIDFLAGS;
5367 
5368     if ( msgid == 0 )
5369       flags |= DPCANCELSEND_ALL;
5370 
5371     return dplay_cancelmsg( This, msgid, flags, 0, 0 );
5372 }
5373 
5374 static HRESULT WINAPI IDirectPlay4AImpl_CancelPriority( IDirectPlay4A *iface, DWORD minprio,
5375         DWORD maxprio, DWORD flags )
5376 {
5377     IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5378     return IDirectPlayX_CancelPriority( &This->IDirectPlay4_iface, minprio, maxprio, flags );
5379 }
5380 
5381 static HRESULT WINAPI IDirectPlay4Impl_CancelPriority( IDirectPlay4 *iface, DWORD minprio,
5382         DWORD maxprio, DWORD flags )
5383 {
5384     IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5385 
5386     if ( flags != 0 )
5387         return DPERR_INVALIDFLAGS;
5388 
5389     return dplay_cancelmsg( This, 0, DPCANCELSEND_PRIORITY, minprio, maxprio );
5390 }
5391 
5392 static const IDirectPlay2Vtbl dp2_vt =
5393 {
5394     IDirectPlay2Impl_QueryInterface,
5395     IDirectPlay2Impl_AddRef,
5396     IDirectPlay2Impl_Release,
5397     IDirectPlay2Impl_AddPlayerToGroup,
5398     IDirectPlay2Impl_Close,
5399     IDirectPlay2Impl_CreateGroup,
5400     IDirectPlay2Impl_CreatePlayer,
5401     IDirectPlay2Impl_DeletePlayerFromGroup,
5402     IDirectPlay2Impl_DestroyGroup,
5403     IDirectPlay2Impl_DestroyPlayer,
5404     IDirectPlay2Impl_EnumGroupPlayers,
5405     IDirectPlay2Impl_EnumGroups,
5406     IDirectPlay2Impl_EnumPlayers,
5407     IDirectPlay2Impl_EnumSessions,
5408     IDirectPlay2Impl_GetCaps,
5409     IDirectPlay2Impl_GetGroupData,
5410     IDirectPlay2Impl_GetGroupName,
5411     IDirectPlay2Impl_GetMessageCount,
5412     IDirectPlay2Impl_GetPlayerAddress,
5413     IDirectPlay2Impl_GetPlayerCaps,
5414     IDirectPlay2Impl_GetPlayerData,
5415     IDirectPlay2Impl_GetPlayerName,
5416     IDirectPlay2Impl_GetSessionDesc,
5417     IDirectPlay2Impl_Initialize,
5418     IDirectPlay2Impl_Open,
5419     IDirectPlay2Impl_Receive,
5420     IDirectPlay2Impl_Send,
5421     IDirectPlay2Impl_SetGroupData,
5422     IDirectPlay2Impl_SetGroupName,
5423     IDirectPlay2Impl_SetPlayerData,
5424     IDirectPlay2Impl_SetPlayerName,
5425     IDirectPlay2Impl_SetSessionDesc
5426 };
5427 
5428 static const IDirectPlay2Vtbl dp2A_vt =
5429 {
5430     IDirectPlay2AImpl_QueryInterface,
5431     IDirectPlay2AImpl_AddRef,
5432     IDirectPlay2AImpl_Release,
5433     IDirectPlay2AImpl_AddPlayerToGroup,
5434     IDirectPlay2AImpl_Close,
5435     IDirectPlay2AImpl_CreateGroup,
5436     IDirectPlay2AImpl_CreatePlayer,
5437     IDirectPlay2AImpl_DeletePlayerFromGroup,
5438     IDirectPlay2AImpl_DestroyGroup,
5439     IDirectPlay2AImpl_DestroyPlayer,
5440     IDirectPlay2AImpl_EnumGroupPlayers,
5441     IDirectPlay2AImpl_EnumGroups,
5442     IDirectPlay2AImpl_EnumPlayers,
5443     IDirectPlay2AImpl_EnumSessions,
5444     IDirectPlay2AImpl_GetCaps,
5445     IDirectPlay2AImpl_GetGroupData,
5446     IDirectPlay2AImpl_GetGroupName,
5447     IDirectPlay2AImpl_GetMessageCount,
5448     IDirectPlay2AImpl_GetPlayerAddress,
5449     IDirectPlay2AImpl_GetPlayerCaps,
5450     IDirectPlay2AImpl_GetPlayerData,
5451     IDirectPlay2AImpl_GetPlayerName,
5452     IDirectPlay2AImpl_GetSessionDesc,
5453     IDirectPlay2AImpl_Initialize,
5454     IDirectPlay2AImpl_Open,
5455     IDirectPlay2AImpl_Receive,
5456     IDirectPlay2AImpl_Send,
5457     IDirectPlay2AImpl_SetGroupData,
5458     IDirectPlay2AImpl_SetGroupName,
5459     IDirectPlay2AImpl_SetPlayerData,
5460     IDirectPlay2AImpl_SetPlayerName,
5461     IDirectPlay2AImpl_SetSessionDesc
5462 };
5463 
5464 static const IDirectPlay3Vtbl dp3_vt =
5465 {
5466     IDirectPlay3Impl_QueryInterface,
5467     IDirectPlay3Impl_AddRef,
5468     IDirectPlay3Impl_Release,
5469     IDirectPlay3Impl_AddPlayerToGroup,
5470     IDirectPlay3Impl_Close,
5471     IDirectPlay3Impl_CreateGroup,
5472     IDirectPlay3Impl_CreatePlayer,
5473     IDirectPlay3Impl_DeletePlayerFromGroup,
5474     IDirectPlay3Impl_DestroyGroup,
5475     IDirectPlay3Impl_DestroyPlayer,
5476     IDirectPlay3Impl_EnumGroupPlayers,
5477     IDirectPlay3Impl_EnumGroups,
5478     IDirectPlay3Impl_EnumPlayers,
5479     IDirectPlay3Impl_EnumSessions,
5480     IDirectPlay3Impl_GetCaps,
5481     IDirectPlay3Impl_GetGroupData,
5482     IDirectPlay3Impl_GetGroupName,
5483     IDirectPlay3Impl_GetMessageCount,
5484     IDirectPlay3Impl_GetPlayerAddress,
5485     IDirectPlay3Impl_GetPlayerCaps,
5486     IDirectPlay3Impl_GetPlayerData,
5487     IDirectPlay3Impl_GetPlayerName,
5488     IDirectPlay3Impl_GetSessionDesc,
5489     IDirectPlay3Impl_Initialize,
5490     IDirectPlay3Impl_Open,
5491     IDirectPlay3Impl_Receive,
5492     IDirectPlay3Impl_Send,
5493     IDirectPlay3Impl_SetGroupData,
5494     IDirectPlay3Impl_SetGroupName,
5495     IDirectPlay3Impl_SetPlayerData,
5496     IDirectPlay3Impl_SetPlayerName,
5497     IDirectPlay3Impl_SetSessionDesc,
5498     IDirectPlay3Impl_AddGroupToGroup,
5499     IDirectPlay3Impl_CreateGroupInGroup,
5500     IDirectPlay3Impl_DeleteGroupFromGroup,
5501     IDirectPlay3Impl_EnumConnections,
5502     IDirectPlay3Impl_EnumGroupsInGroup,
5503     IDirectPlay3Impl_GetGroupConnectionSettings,
5504     IDirectPlay3Impl_InitializeConnection,
5505     IDirectPlay3Impl_SecureOpen,
5506     IDirectPlay3Impl_SendChatMessage,
5507     IDirectPlay3Impl_SetGroupConnectionSettings,
5508     IDirectPlay3Impl_StartSession,
5509     IDirectPlay3Impl_GetGroupFlags,
5510     IDirectPlay3Impl_GetGroupParent,
5511     IDirectPlay3Impl_GetPlayerAccount,
5512     IDirectPlay3Impl_GetPlayerFlags
5513 };
5514 
5515 static const IDirectPlay3Vtbl dp3A_vt =
5516 {
5517     IDirectPlay3AImpl_QueryInterface,
5518     IDirectPlay3AImpl_AddRef,
5519     IDirectPlay3AImpl_Release,
5520     IDirectPlay3AImpl_AddPlayerToGroup,
5521     IDirectPlay3AImpl_Close,
5522     IDirectPlay3AImpl_CreateGroup,
5523     IDirectPlay3AImpl_CreatePlayer,
5524     IDirectPlay3AImpl_DeletePlayerFromGroup,
5525     IDirectPlay3AImpl_DestroyGroup,
5526     IDirectPlay3AImpl_DestroyPlayer,
5527     IDirectPlay3AImpl_EnumGroupPlayers,
5528     IDirectPlay3AImpl_EnumGroups,
5529     IDirectPlay3AImpl_EnumPlayers,
5530     IDirectPlay3AImpl_EnumSessions,
5531     IDirectPlay3AImpl_GetCaps,
5532     IDirectPlay3AImpl_GetGroupData,
5533     IDirectPlay3AImpl_GetGroupName,
5534     IDirectPlay3AImpl_GetMessageCount,
5535     IDirectPlay3AImpl_GetPlayerAddress,
5536     IDirectPlay3AImpl_GetPlayerCaps,
5537     IDirectPlay3AImpl_GetPlayerData,
5538     IDirectPlay3AImpl_GetPlayerName,
5539     IDirectPlay3AImpl_GetSessionDesc,
5540     IDirectPlay3AImpl_Initialize,
5541     IDirectPlay3AImpl_Open,
5542     IDirectPlay3AImpl_Receive,
5543     IDirectPlay3AImpl_Send,
5544     IDirectPlay3AImpl_SetGroupData,
5545     IDirectPlay3AImpl_SetGroupName,
5546     IDirectPlay3AImpl_SetPlayerData,
5547     IDirectPlay3AImpl_SetPlayerName,
5548     IDirectPlay3AImpl_SetSessionDesc,
5549     IDirectPlay3AImpl_AddGroupToGroup,
5550     IDirectPlay3AImpl_CreateGroupInGroup,
5551     IDirectPlay3AImpl_DeleteGroupFromGroup,
5552     IDirectPlay3AImpl_EnumConnections,
5553     IDirectPlay3AImpl_EnumGroupsInGroup,
5554     IDirectPlay3AImpl_GetGroupConnectionSettings,
5555     IDirectPlay3AImpl_InitializeConnection,
5556     IDirectPlay3AImpl_SecureOpen,
5557     IDirectPlay3AImpl_SendChatMessage,
5558     IDirectPlay3AImpl_SetGroupConnectionSettings,
5559     IDirectPlay3AImpl_StartSession,
5560     IDirectPlay3AImpl_GetGroupFlags,
5561     IDirectPlay3AImpl_GetGroupParent,
5562     IDirectPlay3AImpl_GetPlayerAccount,
5563     IDirectPlay3AImpl_GetPlayerFlags
5564 };
5565 
5566 static const IDirectPlay4Vtbl dp4_vt =
5567 {
5568     IDirectPlay4Impl_QueryInterface,
5569     IDirectPlay4Impl_AddRef,
5570     IDirectPlay4Impl_Release,
5571     IDirectPlay4Impl_AddPlayerToGroup,
5572     IDirectPlay4Impl_Close,
5573     IDirectPlay4Impl_CreateGroup,
5574     IDirectPlay4Impl_CreatePlayer,
5575     IDirectPlay4Impl_DeletePlayerFromGroup,
5576     IDirectPlay4Impl_DestroyGroup,
5577     IDirectPlay4Impl_DestroyPlayer,
5578     IDirectPlay4Impl_EnumGroupPlayers,
5579     IDirectPlay4Impl_EnumGroups,
5580     IDirectPlay4Impl_EnumPlayers,
5581     IDirectPlay4Impl_EnumSessions,
5582     IDirectPlay4Impl_GetCaps,
5583     IDirectPlay4Impl_GetGroupData,
5584     IDirectPlay4Impl_GetGroupName,
5585     IDirectPlay4Impl_GetMessageCount,
5586     IDirectPlay4Impl_GetPlayerAddress,
5587     IDirectPlay4Impl_GetPlayerCaps,
5588     IDirectPlay4Impl_GetPlayerData,
5589     IDirectPlay4Impl_GetPlayerName,
5590     IDirectPlay4Impl_GetSessionDesc,
5591     IDirectPlay4Impl_Initialize,
5592     IDirectPlay4Impl_Open,
5593     IDirectPlay4Impl_Receive,
5594     IDirectPlay4Impl_Send,
5595     IDirectPlay4Impl_SetGroupData,
5596     IDirectPlay4Impl_SetGroupName,
5597     IDirectPlay4Impl_SetPlayerData,
5598     IDirectPlay4Impl_SetPlayerName,
5599     IDirectPlay4Impl_SetSessionDesc,
5600     IDirectPlay4Impl_AddGroupToGroup,
5601     IDirectPlay4Impl_CreateGroupInGroup,
5602     IDirectPlay4Impl_DeleteGroupFromGroup,
5603     IDirectPlay4Impl_EnumConnections,
5604     IDirectPlay4Impl_EnumGroupsInGroup,
5605     IDirectPlay4Impl_GetGroupConnectionSettings,
5606     IDirectPlay4Impl_InitializeConnection,
5607     IDirectPlay4Impl_SecureOpen,
5608     IDirectPlay4Impl_SendChatMessage,
5609     IDirectPlay4Impl_SetGroupConnectionSettings,
5610     IDirectPlay4Impl_StartSession,
5611     IDirectPlay4Impl_GetGroupFlags,
5612     IDirectPlay4Impl_GetGroupParent,
5613     IDirectPlay4Impl_GetPlayerAccount,
5614     IDirectPlay4Impl_GetPlayerFlags,
5615     IDirectPlay4Impl_GetGroupOwner,
5616     IDirectPlay4Impl_SetGroupOwner,
5617     IDirectPlay4Impl_SendEx,
5618     IDirectPlay4Impl_GetMessageQueue,
5619     IDirectPlay4Impl_CancelMessage,
5620     IDirectPlay4Impl_CancelPriority
5621 };
5622 
5623 static const IDirectPlay4Vtbl dp4A_vt =
5624 {
5625     IDirectPlay4AImpl_QueryInterface,
5626     IDirectPlay4AImpl_AddRef,
5627     IDirectPlay4AImpl_Release,
5628     IDirectPlay4AImpl_AddPlayerToGroup,
5629     IDirectPlay4AImpl_Close,
5630     IDirectPlay4AImpl_CreateGroup,
5631     IDirectPlay4AImpl_CreatePlayer,
5632     IDirectPlay4AImpl_DeletePlayerFromGroup,
5633     IDirectPlay4AImpl_DestroyGroup,
5634     IDirectPlay4AImpl_DestroyPlayer,
5635     IDirectPlay4AImpl_EnumGroupPlayers,
5636     IDirectPlay4AImpl_EnumGroups,
5637     IDirectPlay4AImpl_EnumPlayers,
5638     IDirectPlay4AImpl_EnumSessions,
5639     IDirectPlay4AImpl_GetCaps,
5640     IDirectPlay4AImpl_GetGroupData,
5641     IDirectPlay4AImpl_GetGroupName,
5642     IDirectPlay4AImpl_GetMessageCount,
5643     IDirectPlay4AImpl_GetPlayerAddress,
5644     IDirectPlay4AImpl_GetPlayerCaps,
5645     IDirectPlay4AImpl_GetPlayerData,
5646     IDirectPlay4AImpl_GetPlayerName,
5647     IDirectPlay4AImpl_GetSessionDesc,
5648     IDirectPlay4AImpl_Initialize,
5649     IDirectPlay4AImpl_Open,
5650     IDirectPlay4AImpl_Receive,
5651     IDirectPlay4AImpl_Send,
5652     IDirectPlay4AImpl_SetGroupData,
5653     IDirectPlay4AImpl_SetGroupName,
5654     IDirectPlay4AImpl_SetPlayerData,
5655     IDirectPlay4AImpl_SetPlayerName,
5656     IDirectPlay4AImpl_SetSessionDesc,
5657     IDirectPlay4AImpl_AddGroupToGroup,
5658     IDirectPlay4AImpl_CreateGroupInGroup,
5659     IDirectPlay4AImpl_DeleteGroupFromGroup,
5660     IDirectPlay4AImpl_EnumConnections,
5661     IDirectPlay4AImpl_EnumGroupsInGroup,
5662     IDirectPlay4AImpl_GetGroupConnectionSettings,
5663     IDirectPlay4AImpl_InitializeConnection,
5664     IDirectPlay4AImpl_SecureOpen,
5665     IDirectPlay4AImpl_SendChatMessage,
5666     IDirectPlay4AImpl_SetGroupConnectionSettings,
5667     IDirectPlay4AImpl_StartSession,
5668     IDirectPlay4AImpl_GetGroupFlags,
5669     IDirectPlay4AImpl_GetGroupParent,
5670     IDirectPlay4AImpl_GetPlayerAccount,
5671     IDirectPlay4AImpl_GetPlayerFlags,
5672     IDirectPlay4AImpl_GetGroupOwner,
5673     IDirectPlay4AImpl_SetGroupOwner,
5674     IDirectPlay4AImpl_SendEx,
5675     IDirectPlay4AImpl_GetMessageQueue,
5676     IDirectPlay4AImpl_CancelMessage,
5677     IDirectPlay4AImpl_CancelPriority
5678 };
5679 
5680 HRESULT dplay_create( REFIID riid, void **ppv )
5681 {
5682     IDirectPlayImpl *obj;
5683     HRESULT hr;
5684 
5685     TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv );
5686 
5687     *ppv = NULL;
5688     obj = HeapAlloc( GetProcessHeap(), 0, sizeof( *obj ) );
5689     if ( !obj )
5690         return DPERR_OUTOFMEMORY;
5691 
5692     obj->IDirectPlay_iface.lpVtbl = &dp_vt;
5693     obj->IDirectPlay2A_iface.lpVtbl = &dp2A_vt;
5694     obj->IDirectPlay2_iface.lpVtbl = &dp2_vt;
5695     obj->IDirectPlay3A_iface.lpVtbl = &dp3A_vt;
5696     obj->IDirectPlay3_iface.lpVtbl = &dp3_vt;
5697     obj->IDirectPlay4A_iface.lpVtbl = &dp4A_vt;
5698     obj->IDirectPlay4_iface.lpVtbl = &dp4_vt;
5699     obj->numIfaces = 1;
5700     obj->ref = 0;
5701     obj->ref2A = 0;
5702     obj->ref2 = 0;
5703     obj->ref3A = 0;
5704     obj->ref3 = 0;
5705     obj->ref4A = 0;
5706     obj->ref4 = 1;
5707 
5708     InitializeCriticalSection( &obj->lock );
5709     obj->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayImpl.lock");
5710 
5711     if ( DP_CreateDirectPlay2( obj ) )
5712         hr = IDirectPlayX_QueryInterface( &obj->IDirectPlay4_iface, riid, ppv );
5713     else
5714         hr = DPERR_NOMEMORY;
5715     IDirectPlayX_Release( &obj->IDirectPlay4_iface );
5716 
5717     return hr;
5718 }
5719 
5720 
5721 HRESULT DP_GetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void **lplpData )
5722 {
5723   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5724 
5725   if( lpPlayer == NULL )
5726   {
5727     return DPERR_INVALIDPLAYER;
5728   }
5729 
5730   *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5731 
5732   return DP_OK;
5733 }
5734 
5735 HRESULT DP_SetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void *lpData )
5736 {
5737   lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5738 
5739   if( lpPlayer == NULL )
5740   {
5741     return DPERR_INVALIDPLAYER;
5742   }
5743 
5744   lpPlayer->lpPData->lpSPPlayerData = lpData;
5745 
5746   return DP_OK;
5747 }
5748 
5749 /***************************************************************************
5750  *  DirectPlayEnumerateAW
5751  *
5752  *  The pointer to the structure lpContext will be filled with the
5753  *  appropriate data for each service offered by the OS. These services are
5754  *  not necessarily available on this particular machine but are defined
5755  *  as simple service providers under the "Service Providers" registry key.
5756  *  This structure is then passed to lpEnumCallback for each of the different
5757  *  services.
5758  *
5759  *  This API is useful only for applications written using DirectX3 or
5760  *  worse. It is superseded by IDirectPlay3::EnumConnections which also
5761  *  gives information on the actual connections.
5762  *
5763  * defn of a service provider:
5764  * A dynamic-link library used by DirectPlay to communicate over a network.
5765  * The service provider contains all the network-specific code required
5766  * to send and receive messages. Online services and network operators can
5767  * supply service providers to use specialized hardware, protocols, communications
5768  * media, and network resources.
5769  *
5770  */
5771 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5772                                      LPDPENUMDPCALLBACKW lpEnumCallbackW,
5773                                      LPVOID lpContext)
5774 {
5775     HKEY   hkResult;
5776     static const WCHAR searchSubKey[] = {
5777 	'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5778 	'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5779 	'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5780 	'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5781     static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5782     static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5783 
5784     DWORD  dwIndex;
5785     FILETIME filetime;
5786 
5787     char  *descriptionA = NULL;
5788     DWORD max_sizeOfDescriptionA = 0;
5789     WCHAR *descriptionW = NULL;
5790     DWORD max_sizeOfDescriptionW = 0;
5791     DWORD sizeOfSubKeyName;
5792     WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5793     LONG  ret_value;
5794     static GUID *guid_cache;
5795     static int cache_count;
5796 
5797     if (!lpEnumCallbackA && !lpEnumCallbackW)
5798     {
5799 	return DPERR_INVALIDPARAMS;
5800     }
5801 
5802     /* Need to loop over the service providers in the registry */
5803     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5804 		      0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5805     {
5806 	/* Hmmm. Does this mean that there are no service providers? */
5807 	ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5808 	return DPERR_GENERIC;
5809     }
5810 
5811     dwIndex = 0;
5812     do
5813     {
5814         sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
5815 	ret_value = RegEnumKeyW(hkResult, dwIndex, subKeyName, sizeOfSubKeyName);
5816 	dwIndex++;
5817     }
5818     while (ret_value == ERROR_SUCCESS);
5819     /* The game Swing from bug 37185 expects GUID values to persist after
5820      * the end of the enumeration. */
5821     if (cache_count < dwIndex)
5822     {
5823 	HeapFree(GetProcessHeap(), 0, guid_cache);
5824 	guid_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID) * dwIndex);
5825 	if (!guid_cache)
5826 	{
5827 	    ERR(": failed to allocate required memory.\n");
5828 	    return DPERR_EXCEPTION;
5829 	}
5830 	cache_count = dwIndex;
5831     }
5832     /* Traverse all the service providers we have available */
5833     dwIndex = 0;
5834     while (1)
5835     {
5836 	HKEY  hkServiceProvider;
5837 	WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5838 	DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5839 
5840         sizeOfSubKeyName = ARRAY_SIZE(subKeyName);
5841 	ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5842 				  NULL, NULL, NULL, &filetime);
5843 	if (ret_value == ERROR_NO_MORE_ITEMS)
5844 	    break;
5845 	else if (ret_value != ERROR_SUCCESS)
5846 	{
5847 	    ERR(": could not enumerate on service provider key.\n");
5848 	    return DPERR_EXCEPTION;
5849 	}
5850 	TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5851 
5852 	/* Open the key for this service provider */
5853 	if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5854 	{
5855 	    ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5856 	    continue;
5857 	}
5858 
5859 	/* Get the GUID from the registry */
5860 	if (RegQueryValueExW(hkServiceProvider, guidKey,
5861 			     NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5862 	{
5863 	    ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5864 	    continue;
5865 	}
5866 	if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5867 	{
5868 	    ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5869 	    continue;
5870 	}
5871 	CLSIDFromString(guidKeyContent, &guid_cache[dwIndex]);
5872 
5873 	/* The enumeration will return FALSE if we are not to continue.
5874 	 *
5875 	 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5876 	 *       and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5877 	 *       I think that it simply means that they are in-line with DirectX 6.0
5878 	 */
5879 	if (lpEnumCallbackA)
5880 	{
5881 	    DWORD sizeOfDescription = 0;
5882 
5883 	    /* Note that this is the A case of this function, so use the A variant to get the description string */
5884 	    if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5885 				 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5886 	    {
5887 		ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5888 		continue;
5889 	    }
5890 	    if (sizeOfDescription > max_sizeOfDescriptionA)
5891 	    {
5892 		HeapFree(GetProcessHeap(), 0, descriptionA);
5893 		max_sizeOfDescriptionA = sizeOfDescription;
5894 	    }
5895 	    descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5896 	    RegQueryValueExA(hkServiceProvider, "DescriptionA",
5897 			     NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5898 
5899 	    if (!lpEnumCallbackA(&guid_cache[dwIndex], descriptionA, 6, 0, lpContext))
5900 		goto end;
5901 	}
5902 	else
5903 	{
5904 	    DWORD sizeOfDescription = 0;
5905 
5906 	    if (RegQueryValueExW(hkServiceProvider, descW,
5907 				 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5908 	    {
5909 		ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5910 		continue;
5911 	    }
5912 	    if (sizeOfDescription > max_sizeOfDescriptionW)
5913 	    {
5914 		HeapFree(GetProcessHeap(), 0, descriptionW);
5915 		max_sizeOfDescriptionW = sizeOfDescription;
5916 	    }
5917 	    descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5918 	    RegQueryValueExW(hkServiceProvider, descW,
5919 			     NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5920 
5921 	    if (!lpEnumCallbackW(&guid_cache[dwIndex], descriptionW, 6, 0, lpContext))
5922 		goto end;
5923 	}
5924 
5925       dwIndex++;
5926   }
5927 
5928  end:
5929     HeapFree(GetProcessHeap(), 0, descriptionA);
5930     HeapFree(GetProcessHeap(), 0, descriptionW);
5931 
5932     return DP_OK;
5933 }
5934 
5935 /***************************************************************************
5936  *  DirectPlayEnumerate  [DPLAYX.9]
5937  *  DirectPlayEnumerateA [DPLAYX.2]
5938  */
5939 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5940 {
5941     TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5942 
5943     return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5944 }
5945 
5946 /***************************************************************************
5947  *  DirectPlayEnumerateW [DPLAYX.3]
5948  */
5949 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5950 {
5951     TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5952 
5953     return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5954 }
5955 
5956 typedef struct tagCreateEnum
5957 {
5958   LPVOID  lpConn;
5959   LPCGUID lpGuid;
5960 } CreateEnumData, *lpCreateEnumData;
5961 
5962 /* Find and copy the matching connection for the SP guid */
5963 static BOOL CALLBACK cbDPCreateEnumConnections(
5964     LPCGUID     lpguidSP,
5965     LPVOID      lpConnection,
5966     DWORD       dwConnectionSize,
5967     LPCDPNAME   lpName,
5968     DWORD       dwFlags,
5969     LPVOID      lpContext)
5970 {
5971   lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5972 
5973   if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5974   {
5975     TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5976 
5977     lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5978                                 dwConnectionSize );
5979     CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5980 
5981     /* Found the record that we were looking for */
5982     return FALSE;
5983   }
5984 
5985   /* Haven't found what were looking for yet */
5986   return TRUE;
5987 }
5988 
5989 
5990 /***************************************************************************
5991  *  DirectPlayCreate [DPLAYX.1]
5992  *
5993  */
5994 HRESULT WINAPI DirectPlayCreate
5995 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5996 {
5997   HRESULT hr;
5998   LPDIRECTPLAY3A lpDP3A;
5999   CreateEnumData cbData;
6000 
6001   TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
6002 
6003   if( pUnk != NULL )
6004   {
6005     return CLASS_E_NOAGGREGATION;
6006   }
6007 
6008   if( (lplpDP == NULL) || (lpGUID == NULL) )
6009   {
6010     return DPERR_INVALIDPARAMS;
6011   }
6012 
6013   if ( dplay_create( &IID_IDirectPlay, (void**)lplpDP ) != DP_OK )
6014     return DPERR_UNAVAILABLE;
6015 
6016   if( IsEqualGUID( &GUID_NULL, lpGUID ) )
6017   {
6018     /* The GUID_NULL means don't bind a service provider. Just return the
6019        interface as is */
6020     return DP_OK;
6021   }
6022 
6023   /* Bind the desired service provider since lpGUID is non NULL */
6024   TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
6025 
6026   /* We're going to use a DP3 interface */
6027   hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
6028                                     (LPVOID*)&lpDP3A );
6029   if( FAILED(hr) )
6030   {
6031     ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
6032     return hr;
6033   }
6034 
6035   cbData.lpConn = NULL;
6036   cbData.lpGuid = lpGUID;
6037 
6038   /* We were given a service provider, find info about it... */
6039   hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
6040                                      &cbData, DPCONNECTION_DIRECTPLAY );
6041   if( ( FAILED(hr) ) ||
6042       ( cbData.lpConn == NULL )
6043     )
6044   {
6045     ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
6046     IDirectPlayX_Release( lpDP3A );
6047     return DPERR_UNAVAILABLE;
6048   }
6049 
6050   /* Initialize the service provider */
6051   hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
6052   if( FAILED(hr) )
6053   {
6054     ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
6055     HeapFree( GetProcessHeap(), 0, cbData.lpConn );
6056     IDirectPlayX_Release( lpDP3A );
6057     return hr;
6058   }
6059 
6060   /* Release our version of the interface now that we're done with it */
6061   IDirectPlayX_Release( lpDP3A );
6062   HeapFree( GetProcessHeap(), 0, cbData.lpConn );
6063 
6064   return DP_OK;
6065 }
6066