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