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