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