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