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